UILabel默认字距与CATextLayer不同

时间:2012-05-07 05:29:56

标签: iphone ios uikit core-text

我有一个UILabel字符串'LA'。我还有CATextLayerNSAttributedString分配给其string媒体资源的相同字符。 UILabel中的字距调整与CATextLayer明显不同。这是代码。

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 
    // UILabel
    //
    UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, 280, 100)];
    label1.text = @"LA";
    label1.backgroundColor = [UIColor clearColor];
    label1.font = [UIFont fontWithName:@"Futura" size:90.0];
    [self.view addSubview:label1];

    //
    // CATextLayer
    //
    UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(20, 130, 280, 100)];
    label2.backgroundColor = [UIColor clearColor];
    CATextLayer *textLayer = [[CATextLayer alloc] init];
    textLayer.frame = label2.layer.bounds;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    [label2.layer addSublayer:textLayer];
    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"LA"];
    CTFontRef aFont = CTFontCreateWithName((__bridge CFStringRef)@"Futura", 90.0, NULL);
    [string addAttribute:(NSString*)kCTFontAttributeName value:(__bridge id)aFont range:NSMakeRange(0, [string length])];
    textLayer.string = string;
    [self.view addSubview:label2];
}

这是结果的an image

为什么这两种方法之间的字距不同以及我在CATextLayer示例中做错了什么?

3 个答案:

答案 0 :(得分:3)

UIKit通常使用WebKit进行文本渲染(在this crash log)中可见),最有可能出于性能原因。如果您确实需要超精度,那么有一些custom UILabel reimplementations使用CoreText作为它的后端。

修改 从iOS7开始,这不再是真的,因为UILabel使用TextKit进行渲染,它也基于CoreText。

答案 1 :(得分:1)

您应该为NSMutableAttributedString添加属性。

对于字距调整:

    CGFloat characterspacing = 10.0f;
    CFNumberRef num = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt8Type,&characterspacing);
    [string addAttribute:(id)kCTKernAttributeName value:(id)num range:NSMakeRange(0 , [string length])];
    CFRelease(num);

如果您还需要行间距,或设置LineBreadMode:

    CTLineBreakMode linebreak = kCTLineBreakByCharWrapping;
    CTParagraphStyleSetting linebreakStyle;
    linebreakStyle.spec = kCTParagraphStyleSpecifierLineBreakMode;
    linebreakStyle.valueSize = sizeof(linebreak);
    linebreakStyle.value = &linebreak;

    CTParagraphStyleSetting lineSpaceStyle;
    CGFloat linespacing = self.linesSpacing;
    lineSpaceStyle.spec = kCTParagraphStyleSpecifierLineSpacingAdjustment;
    lineSpaceStyle.valueSize = sizeof(linespacing);
    lineSpaceStyle.value =&linespacing;
    CTParagraphStyleSetting settings[ ] ={linebreakStyle,lineSpaceStyle};
    CTParagraphStyleRef style = CTParagraphStyleCreate(settings ,2);
    [string addAttribute:(id)kCTParagraphStyleAttributeName value:(id)style range:NSMakeRange(0 , [string length])];
    CFRelease(style);

最后,您可能需要计算关于您的字距,行间距和LineBreakMode的行数(linenum):

CTFramesetterRef myframesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGMutablePathRef leftColumnPath = CGPathCreateMutable();
CGPathAddRect(leftColumnPath, NULL ,CGRectMake(0 , 0 , Lable.frame.size.width, MAXFLOAT));
CTFrameRef leftFrame = CTFramesetterCreateFrame(myframesetter,CFRangeMake(0, 0), leftColumnPath , NULL);
CFArrayRef lines = CTFrameGetLines(leftFrame);
linenum = (int)CFArrayGetCount(lines);
CFRelease(myframesetter);
CFRelease(leftFrame);
CGPathRelease(leftColumnPath);

答案 2 :(得分:0)

与使用UIKit绘制字符串相比,Core Text非常不同,可能是因为它来自Core Foundation而不是AppKitUIKit。我确实理解您使用标签在字符串上执行度量标准的要求。对我来说,唯一的解决方案是匹配属性字符串中UILabel的字距,遗憾的是我不知道确切的值,但您可以使用此属性更改该值kCTKernAttributeName。你也应该注意可能不一样的联运 将该值强制为匹配的字距调整,您可以拥有正确的行为。如果您想要相反(匹配CT字距调整),您应该进行一些数学运算,稍后应用于标签UIEdgeInset以计算正确的标签。
希望这会有所帮助。