22

これまでの私のすべての調査は、これを正確に行うことは不可能であることを示しているようです。最初に利用できるオプションは次の 2 つだけでした。

a) CATextLayer のレイアウト マネージャーの使用 - 4.0 の時点で iOS では使用できません

b) sizeWithFont:constrainedToSize:lineBreakMode: を使用し、ここで返されたサイズに従って CATextLayer のフレームを調整します。

オプション (b) は最も単純なアプローチであり、うまくいくはずです。結局、UILabels と完全に連携します。しかし、同じフレーム計算を CATextLayer に適用すると、フレームは常に予想または必要より少し大きくなることが判明しました。

結局のところ、(同じフォントとサイズの) CATextLayers と UILabels の行間隔は異なります。その結果、sizeWithFont (行間隔の計算が UILabels の計算と一致する) は、CATextLayers の予想されるサイズを返しません。

これは、CATextLayer に対して UILabel を使用して同じテキストを出力し、結果を比較することでさらに証明されます。最初の行のテキストは完全に重なっています (同じフォントです) が、CATextLayer の行間隔は UILabel よりも少しだけ短くなっています。(申し訳ありませんが、スクリーンショットには機密データが含まれているため、現在スクリーンショットをアップロードできません。現在、クリーンなスクリーンショットを取得するためのサンプル プロジェクトを作成する時間がありません。後世のために後でアップロードします。時間はあります)

これは奇妙な違いですが、そこで使用する NSAttributedString に適切な属性を指定することで CATextLayer の間隔を調整できると思っていましたが、そうではないようです。CFStringAttributes.h を調べると、行間隔に関連する可能性のある単一の属性が見つかりません。

結論:

そのため、レイヤーをテキストに合わせる必要があるシナリオでは、iOS で CATextLayer を使用することはできないようです。私はこれで正しいですか、それとも何か不足していますか?

PS:

  1. CATextLayer と NSAttributedString を使用したかった理由は、表示される文字列が異なるポイントで異なる色で表示されるためです。いつものように手で文字列を描画することに戻る必要があると思います....もちろん、適切な行の高さを取得するために 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 に答える
-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 に答える