12

UILabel文字列「LA」のがあります。またCATextLayer、同じ文字がプロパティにNSAttributedString割り当てられてい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];
}

これが結果の画像です。

これら2つの方法でカーニングが異なるのはなぜですか。また、このCATextLayer例で何が間違っているのでしょうか。

4

3 に答える 3

3

UIKitは通常、テキストのレンダリングにWebKitを使用します(このクラッシュログに表示されます)。おそらくパフォーマンス上の理由からです。超高精度が本当に必要な場合は、バックエンドとして使用するカスタムのUILabel再実装がいくつかあります。CoreText

編集:UILabel iOS7以降、CoreTextに基づくレンダリングにTextKitを使用しているため、 これは当てはまりません。

于 2012-10-06T18:36:52.230 に答える
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);
于 2013-03-04T06:44:05.800 に答える
0

UIKitCore Textを使用して文字列を描画する場合と比較すると、実際には大きくCore Foundation異なりAppKitますUIKit。文字列に対してメトリックのハードジョブを実行するためにラベルを使用するための要件を理解しています。私にとっての唯一の解決策はUILabel、属性付き文字列のカーニングを一致させることです。残念ながら、正確な値はわかりませんが、このプロパティを使用してその値を変更できます kCTKernAttributeName。同じではない可能性のあるインターラインにも注意を払う必要があります。
その値を一致するカーニングに強制すると、正しい動作をすることができます。反対の(CTカーニングに一致する)必要がある場合は、後でラベルaに適用してUIEdgeInset正しいラベルを計算するために、いくつかの計算を行う必要があります。
お役に立てれば。

于 2012-05-29T05:37:22.130 に答える