iOS でテキストに合わせて CATextLayer のサイズを変更する 質問する

iOS でテキストに合わせて CATextLayer のサイズを変更する 質問する

これまでの私の調査では、これを正確に行うことは不可能であることがわかりました。当初、私に選択できる選択肢は次の 2 つだけでした。

a) CATextLayer のレイアウト マネージャーを使用する - iOS 4.0 以降では利用できません

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

オプション (b) は最も単純なアプローチなので、機能するはずです。結局のところ、UILabels では完璧に機能します。しかし、同じフレーム計算を CATextLayer に適用すると、フレームは常に予想または必要以上に大きくなりました。

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

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

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

結論:

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

追伸:

  1. CATextLayer と NSAttributedString を使用したかった理由は、表示される文字列がポイントごとに異なる色で表示されるためです。いつものように手動で文字列を描画するしかないと思います... もちろん、sizeWithFont の結果をハッキングして適切な行の高さを取得するオプションは常にあります。

  2. 投稿を読みやすくするために、「コード」タグを少し乱用します。

  3. 投稿に「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];
}

ありがとう。

おすすめ記事