22

到目前为止,我所有的研究似乎都表明不可能准确地做到这一点。一开始我仅有的两个选择是:

a) 为 CATextLayer 使用布局管理器 - 自 4.0 起在 iOS 上不可用

b) 使用 sizeWithFont:constrainedToSize:lineBreakMode: 并根据此处返回的大小调整 CATextLayer 的边框。

选项 (b) 是最简单的方法,应该可行。毕竟,它与 UILabel 完美配合。但是当我对 CATextLayer 应用相同的框架计算时,框架总是比预期或需要的大一点。

事实证明,CATextLayers 和 UILabels 中的行间距(对于相同的字体和大小)是不同的。因此,sizeWithFont(其行距计算将与 UILabel 的行距计算匹配)不会返回 CATextLayers 的预期大小。

通过使用 UILabel 打印相同的文本,而不是 CATextLayer 并比较结果,进一步证明了这一点。第一行中的文本完全重叠(它是相同的字体),但 CATextLayer 中的行距仅比 UILabel 中的短一点。(对不起,我现在不能上传截图,因为我已经包含机密数据,而且我目前没有时间制作示例项目来获得干净的截图。我会稍后上传它们以供后人使用,当我有时间)

这是一个奇怪的区别,但我认为可以通过为我在那里使用的 NSAttributedString 指定适当的属性来调整 CATextLayer 中的间距,但情况似乎并非如此。查看 CFStringAttributes.h 我找不到可能与行距相关的单个属性。

底线:

因此,在需要图层适合其文本的情况下,似乎不可能在 iOS 上使用 CATextLayer。我是对的还是我错过了什么?

PS:

  1. 我想使用 CATextLayer 和 NSAttributedString's 的原因是因为要显示的字符串在不同的点上会有不同的颜色。我想我只需要像往常一样重新手动绘制字符串......当然,总是可以选择从 sizeWithFont 获取结果以获得正确的行高。

  2. 稍微滥用“代码”标签以使帖子更具可读性。

  3. 我无法用“CATextLayer”标记帖子——令人惊讶的是,目前不存在这样的标签。如果有足够声誉的人碰到这篇文章,请相应地标记它。

4

4 回答 4

18

试试这个:

- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth withAttributedString:(NSAttributedString *)attributedString {
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) attributedString); 
    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, CGFLOAT_MAX), NULL);
    CFRelease(framesetter);
    return suggestedSize.height;
}

您必须将 NSString 转换为 NSAttributedString。在 的情况下CATextLayer,您可以使用以下CATextLayer子类方法:

- (NSAttributedString *)attributedString {

    // If string is an attributed string
    if ([self.string isKindOfClass:[NSAttributedString class]]) {
        return self.string;
    }

    // Collect required parameters, and construct an attributed string
    NSString *string = self.string;
    CGColorRef color = self.foregroundColor;
    CTFontRef theFont = self.font;
    CTTextAlignment alignment;

    if ([self.alignmentMode isEqualToString:kCAAlignmentLeft]) {
        alignment = kCTLeftTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentRight]) {
        alignment = kCTRightTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentCenter]) {
        alignment = kCTCenterTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentJustified]) {
        alignment = kCTJustifiedTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentNatural]) {
        alignment = kCTNaturalTextAlignment;
    }

    // Process the information to get an attributed string
    CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

    if (string != nil)
        CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)string);

    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTForegroundColorAttributeName, color);
    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTFontAttributeName, theFont);

    CTParagraphStyleSetting settings[] = {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment};
    CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTParagraphStyleAttributeName, paragraphStyle);    
    CFRelease(paragraphStyle);

    NSMutableAttributedString *ret = (NSMutableAttributedString *)attrString;

    return [ret autorelease];
}

HTH。

于 2011-12-19T09:54:58.897 回答
2

我有一个更简单的解决方案,它可能对你有用,也可能对你不起作用。

如果你没有用 CATextLayer 做任何你不能做 UILabel 的特殊事情,而是制作一个 CALayer 并将 UILabel 的层添加到 CALayer

UILabel*label = [[UILabel alloc]init];

//Do Stuff to label

CALayer *layer = [CALayer layer];

//Set Size/Position

[layer addSublayer:label.layer];

//Do more stuff to layer
于 2012-01-28T21:17:05.280 回答
0

有了LabelKit,您就不再需要CATextLayer了。不再有错误的行距和更宽的字符,所有这些都以与 UILabel 相同的方式绘制,同时仍然具有动画效果。

于 2019-07-21T03:44:25.510 回答
-2

这个页面给了我足够的创建一个简单的水平居中 CATextLayer: http ://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html

- (void)drawInContext:(CGContextRef)ctx {
  CGFloat height, fontSize;

  height = self.bounds.size.height;
  fontSize = self.fontSize;

  CGContextSaveGState(ctx);
  CGContextTranslateCTM(ctx, 0.0, (fontSize-height)/2.0 * -1.0);
  [super drawInContext:ctx];
  CGContextRestoreGState(ctx);
}
于 2011-09-30T07:31:37.273 回答