10

ドキュメントによると、CTFramesetterSuggestFrameSizeWithConstraints ()「文字列範囲に必要なフレームサイズを決定します」。

残念ながら、この関数によって返されるサイズは決して正確ではありません。これが私がやっていることです:

    NSAttributedString *string = [[[NSAttributedString alloc] initWithString:@"lorem ipsum" attributes:nil] autorelease];
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef) string);
    CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(rect.size.width, CGFLOAT_MAX), NULL);

返されるサイズは常に正しい幅が計算されますが、高さは常に予想よりわずかに短くなります。

これは、このメソッドを使用する正しい方法ですか?

Core Text をレイアウトする他の方法はありますか?

この方法で問題が発生するのは私だけではないようです。https://devforums.apple.com/message/181450を参照してください。

編集: を使用して Quartz で同じ文字列を測定しsizeWithFont:、属性付き文字列と Quartz の両方に同じフォントを指定しました。私が受け取った測定値は次のとおりです。

コア テキスト: 133.569336 x 16.592285

クォーツ:135.000000×31.000000

4

6 に答える 6

14

これを試してください..うまくいくようです:

+(CGFloat)heightForAttributedString:(NSAttributedString *)attrString forWidth:(CGFloat)inWidth
{
    CGFloat H = 0;

    // Create the framesetter with the attributed string.
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) attrString); 

    CGRect box = CGRectMake(0,0, inWidth, CGFLOAT_MAX);

    CFIndex startIndex = 0;

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, box);

    // Create a frame for this column and draw it.
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(startIndex, 0), path, NULL);

    // Start the next frame at the first character not visible in this frame.
    //CFRange frameRange = CTFrameGetVisibleStringRange(frame);
    //startIndex += frameRange.length;

    CFArrayRef lineArray = CTFrameGetLines(frame);
    CFIndex j = 0, lineCount = CFArrayGetCount(lineArray);
    CGFloat h, ascent, descent, leading;

    for (j=0; j < lineCount; j++)
    {
        CTLineRef currentLine = (CTLineRef)CFArrayGetValueAtIndex(lineArray, j);
        CTLineGetTypographicBounds(currentLine, &ascent, &descent, &leading);
        h = ascent + descent + leading;
        NSLog(@"%f", h);
        H+=h;
    }

    CFRelease(frame);
    CFRelease(path);
    CFRelease(framesetter);


    return H;
}
于 2010-11-18T12:58:12.763 に答える
5

1行のフレームの場合、これを試してください:

line = CTLineCreateWithAttributedString((CFAttributedStringRef) string);
CGFloat ascent;
CGFloat descent;
CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
CGFloat height = ascent+descent;
CGSize textSize = CGSizeMake(width,height);

複数行のフレームの場合は、行のリードも追加する必要があります ( Core Text Programming Guideのサンプル コードを参照してください) 。

何らかの理由で、CTFramesetterSuggestFrameSizeWithConstraints()上昇と下降の差を使用して高さを計算しています。

CGFloat wrongHeight = ascent-descent;
CGSize textSize = CGSizeMake(width, wrongHeight);

それはバグでしょうか?

フレームの幅に関して他にも問題があります。特別な場合にのみ表示されるため、チェックアウトする価値があります。詳細については、この質問を参照してください。

于 2010-05-05T02:45:02.663 に答える
3

問題は、テキストを測定する前に段落スタイルをテキストに適用する必要があることです。そうしないと、デフォルトの先頭の 0.0 が取得されます。https://stackoverflow.com/a/10019378/1313863のこの質問の複製に対する回答で、これを行う方法のコードサンプルを提供しました。

于 2012-04-04T21:21:13.413 に答える
0

奇妙に思えるかもしれませんが、ceil最初に関数を使用してから高さに +1 を追加すると、常に機能することがわかりました。多くのサードパーティ API がこのトリックを使用しています。

于 2011-09-04T08:04:14.160 に答える
0

復活。

線をフレーム内のどこに配置するかを最初に決定するとき、Core Text は線の起点を計算する目的で上昇と下降をマッサージしているようです。特に、0.2*(ascent+descent) が上昇に追加され、下降と結果の上昇の両方が によって変更されfloor(x + 0.5)、これらの調整された上昇と下降に基づいてベースライン位置が計算されるようです。これらのステップは両方とも、その性質がよくわからない特定の条件の影響を受けます。また、数日前に調べただけなのに、どの時点で段落スタイルが考慮されるかを忘れてしまいました。

私はすでに、ラインをベースラインから開始することだけを考えており、実際のラインがどこに着地するかを理解しようとはしていません。残念ながら、これではまだ十分ではないようです。段落スタイルは に反映されずCTLineGetTypographicBounds()、Klee のようにゼロ以外の先頭を持つフォントは、パス rect を横切ってしまいます! これについてどうすればよいかわかりません...おそらく別の質問です。

アップデート

適切な行の境界を取得しているようですCTLineGetBoundsWithOptions(line, 0)が、完全ではありません: 行間にギャップがあり、一部のフォント (Klee も同様) ではギャップが負であり、行が重なっています... これについてどうすればよいかわかりません。:| せめて少しは近づいた??

それでも段落スタイルは考慮されません >:|

CTLineGetBoundsWithOptions()Apple のドキュメンテーション サイトにはリストされていません。おそらく、ドキュメンテーション ジェネレーターの現在のバージョンのバグが原因です。ただし、これは完全に文書化された API です — ヘッダー ファイルで見つけることができ、WWDC 2012 セッション 226 で詳細に議論されました。

どのオプションも私たちには関係ありません: 特定のフォント デザインの選択を考慮して、境界 rect を減らします (または、 new の場合は、境界 rect をランダムに増やしますkCTLineBoundsIncludeLanguageExtents)。ただし、一般的に便利なオプションの 1 つは ですkCTLineBoundsUseGlyphPathBounds。これは a と同等ですが、CTLineGetImageBounds()a を指定する必要はありCGContextません (したがって、既存のテキスト マトリックスや CTM の影響を受けません)。

于 2017-01-07T18:17:57.743 に答える