如何在 iOS 中渲染拉伸文本?
给定一个矩形区域,我想使用特定字体渲染一些文本,并让渲染的文本填充矩形。如下图所示:
- 不同
- 这与仅更改字体大小将其渲染为位图 然后缩放它不是一个选项(它看起来很糟糕)
- 矢量图形是做到这一点的方法
解决
方案我想出了以下似乎适合我的目的。该代码绘制一行文本缩放以填充边界。子类 UIView
并替换 drawRect
如下。
- (void)drawRect:(CGRect)rect
{
[self drawScaledString:@"Abcde"];
}
- (void)drawScaledString:(NSString *)string
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
NSAttributedString *attrString = [self generateAttributedString:string];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attrString, CFRangeMake(0, string.length),
kCTForegroundColorAttributeName, [UIColor redColor].CGColor);
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef) attrString);
// CTLineGetTypographicBounds doesn't give correct values,
// using GetImageBounds instead
CGRect imageBounds = CTLineGetImageBounds(line, context);
CGFloat width = imageBounds.size.width;
CGFloat height = imageBounds.size.height;
CGFloat padding = 0;
width += padding;
height += padding;
float sx = self.bounds.size.width / width;
float sy = self.bounds.size.height / height;
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 1, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextScaleCTM(context, sx, sy);
CGContextSetTextPosition(context, -imageBounds.origin.x + padding/2, -imageBounds.origin.y + padding/2);
CTLineDraw(line, context);
CFRelease(line);
}
- (NSAttributedString *)generateAttributedString:(NSString *)string
{
CTFontRef helv = CTFontCreateWithName(CFSTR("Helvetica-Bold"),20, NULL);
CGColorRef color = [UIColor blackColor].CGColor;
NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)helv, (NSString *)kCTFontAttributeName,
color, (NSString *)kCTForegroundColorAttributeName,
nil];
NSAttributedString *attrString = [[[NSMutableAttributedString alloc]
initWithString:string
attributes:attributesDict] autorelease];
return attrString;
}
用法示例:
CGRect rect = CGRectMake(0, 0, 50, 280);
MyCTLabel *label = [[MyCTLabel alloc] initWithFrame:rect];
label.backgroundColor = [UIColor whiteColor];
[self addSubview:label];
Given a rectangular area, I want to render some text using a specific font and have the rendered text fill out the rectangle. As in the image below:
- This is not the same as just changing font size
- Rendering it as a bitmap and then scale it is not an option (it looks horrible)
- Vector graphics is the way to do it
Solution
I came up with the following which seems to work for my purposes. The code draws a single line of text scaling to fill the bounds. Subclass UIView
and replace drawRect
as follows.
- (void)drawRect:(CGRect)rect
{
[self drawScaledString:@"Abcde"];
}
- (void)drawScaledString:(NSString *)string
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
NSAttributedString *attrString = [self generateAttributedString:string];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attrString, CFRangeMake(0, string.length),
kCTForegroundColorAttributeName, [UIColor redColor].CGColor);
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef) attrString);
// CTLineGetTypographicBounds doesn't give correct values,
// using GetImageBounds instead
CGRect imageBounds = CTLineGetImageBounds(line, context);
CGFloat width = imageBounds.size.width;
CGFloat height = imageBounds.size.height;
CGFloat padding = 0;
width += padding;
height += padding;
float sx = self.bounds.size.width / width;
float sy = self.bounds.size.height / height;
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 1, self.bounds.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextScaleCTM(context, sx, sy);
CGContextSetTextPosition(context, -imageBounds.origin.x + padding/2, -imageBounds.origin.y + padding/2);
CTLineDraw(line, context);
CFRelease(line);
}
- (NSAttributedString *)generateAttributedString:(NSString *)string
{
CTFontRef helv = CTFontCreateWithName(CFSTR("Helvetica-Bold"),20, NULL);
CGColorRef color = [UIColor blackColor].CGColor;
NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)helv, (NSString *)kCTFontAttributeName,
color, (NSString *)kCTForegroundColorAttributeName,
nil];
NSAttributedString *attrString = [[[NSMutableAttributedString alloc]
initWithString:string
attributes:attributesDict] autorelease];
return attrString;
}
Example usage:
CGRect rect = CGRectMake(0, 0, 50, 280);
MyCTLabel *label = [[MyCTLabel alloc] initWithFrame:rect];
label.backgroundColor = [UIColor whiteColor];
[self addSubview:label];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以设置 UILabel 变换属性并缩放宽度:
You can set the UILabel transform property and scale the width:
你可以试试CoreText。获取一个 CTFramesetter,计算其矩形,然后计算将该矩形压缩到所需边界所需的仿射变换,并将其设置为 CTM。然后,当您绘制文本时,它应该以最高质量适当拉伸。
You could try CoreText. Get a
CTFramesetter
, calculate its rect, then calculate the affine transform necessary to compress that rect into the bounds you want and set that as the CTM. Then when you draw the text, it should stretch it appropriately at full quality.您还可以尝试使用 UILabel 的
@property(nonatomic) BOOL adjustmentFontSizeToFitWidth
和@propertyminimumFontSize
最初,您可以为 font 属性设置更高的值,并初始化
minimumFontSize
具有最小字体值。you can also try with the UILabel's
@property(nonatomic) BOOL adjustsFontSizeToFitWidth
and@property minimumFontSize
Initially you can set the much higher value for font property and also initialize the
minimumFontSize
with a minimum font value.