【问题标题】:Resize CATextLayer to fit text on iOS调整 CATextLayer 的大小以适应 iOS 上的文本
【发布时间】:2011-06-01 08:07:46
【问题描述】:

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

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”标记帖子 - 令人惊讶的是,目前不存在此类标记。如果有足够声誉的人碰到这篇文章,请相应地标记它。

【问题讨论】:

  • 我刚刚遇到了这个问题……争分夺秒。
  • @All,如果不清楚,该问题严格涉及垂直调整固定宽度的 CATextLayer 的大小,用于不同长度/属性的字符串。

标签: ios4 sizewithfont catextlayer


【解决方案1】:

试试这个:

- (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。

【讨论】:

  • 对不起,已经有一段时间了,我目前没有代码或时间来测试这个。不过,我一定会回来查看的。同时,如果遇到此答案的其他人可以验证它是否有效,我会将其标记为“已回答”。
  • 6 个月后,我终于再次遇到了这个问题。 :) 解决方案奏效了。非常感谢穆斯塔法!!
【解决方案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

【讨论】:

  • 啊,看。正如我的问题底部所指出的,我特别需要使用 CATextLayers 来实现其精美的格式化功能。否则 UILabel 会做得很好。无论如何,这个问题发布已经很久了,到目前为止,唯一有希望的线索是@Mustafa's。悲惨的是,我已经有很长时间没能试一试了。有人愿意吗?
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    这个页面足以让我创建一个简单的水平居中 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);
    }
    

    【讨论】:

    • 抱歉,我认为这不能回答问题。问题是关于垂直调整 CATextLayer 的大小以换行/适合任何字符串,而答案是垂直对齐 - 这也是单行 - 文本。
    猜你喜欢
    • 2018-09-04
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    相关资源
    最近更新 更多