调整CATextLayer的大小以适合iOS上的文本

问题描述

| 到目前为止,我所有的研究似乎都表明不可能准确地做到这一点。一开始对我来说只有两个选择:   a)为CATextLayer使用布局管理器-从4.0版本开始在iOS上不可用      b)使用sizeWithFont:constrainedToSize:lineBreakMode:并根据此处返回的大小调整CATextLayer的框架。 选项(b)是最简单的方法,应该起作用。毕竟,它与UILabels完美配合。但是,当我将相同的帧计算应用于CATextLayer时,该帧总是比预期或需要的要大一些。 事实证明,CATextLayers和UILabels中的行距(对于相同的字体和大小)是不同的。结果,sizeWithFont(其行距计算将与UILabels的行距计算匹配)不会返回CATextLayers的预期大小。 通过使用UILabel打印相同的文本(相对于CATextLayer)并比较结果,可以进一步证明这一点。第一行中的文本完全重叠(它是相同的字体),但是CATextLayer中的行距仅比UILabel中的短。 (对不起,我现在无法上传屏幕截图,因为我已经包含了机密数据,并且我目前没有时间制作示例项目来获取清晰的屏幕截图。我稍后将其上传以用于有时间的话,后代) 这是一个怪异的区别,但是我认为可以通过为我在此处使用的NSAttributedString指定适当的属性来调整CATextLayer中的间距,但这似乎并非如此。调查CFStringAttributes.h我找不到与行间距有关的单个属性。 底线: 因此,在要求图层适合其文本的情况下,似乎无法在iOS上使用CATextLayer。我是对的还是错过了什么? 附言: 我之所以要使用CATextLayer和NSAttributedString \,是因为要显示的字符串在不同点的颜色不同。我想我只需要像往常一样手动绘制字符串即可。...当然,总有一种选择,可以从sizeWithFont修改结果以获取正确的行高。 稍微滥用\'code \'标记可使帖子更具可读性。 我无法使用\'CATextLayer \'标记帖子-令人惊讶的是,目前尚无此类标记。如果有足够声誉的人进入此职位,请相应地对其进行标记。     

解决方法

        尝试这个:
- (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
,可以使用以下ѭ1following子类方法:
- (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,(CFStringRef)string);

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

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

    NSMutableAttributedString *ret = (NSMutableAttributedString *)attrString;

    return [ret autorelease];
}
HTH。     ,        我有一个简单得多的解决方案,它可能对您不起作用。 如果您没有对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
    ,        使用LabelKit,您不再需要
CATextLayer
。不再有错误的行距和更宽的字符,所有这些都以与UILabel相同的方式绘制,同时仍具有动画效果。     ,        该页面使我足够创建一个水平居中的简单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);
}