Core Text's CTFramesetterSuggestFrameSizeWithConstraints() returns incorrect size every time

According to the docs, CTFramesetterSuggestFrameSizeWithConstraints () "determines the frame size needed for a string range".

Unfortunately the size returned by this function is never accurate. Here is what I am doing:

    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);

The returned size always has the correct width calculated, however the height is always slightly shorter than what is expected.

Is this the correct way to use this method?

Is there any other way to layout Core Text?

Seems I am not the only one to run into problems with this method. See https://devforums.apple.com/message/181450.

Edit: I measured the same string with Quartz using sizeWithFont: , supplying the same font to both the attributed string, and to Quartz. Here are the measurements I received:

Core Text: 133.569336 x 16.592285

Quartz: 135.000000 x 31.000000


试试这个..似乎工作:

+(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;
}

For a single line frame, try this:

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

For multiline frames, you also need to add the line's lead (see a sample code in Core Text Programming Guide)

For some reason, CTFramesetterSuggestFrameSizeWithConstraints() is using the difference in ascent and descent to calculate the height:

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

It could be a bug?

I'm having some other problems with the width of the frame; It's worth checking out as it only shows in special cases. See this question for more.


The problem is that you have to apply a paragraph style to the text before you measure it. If you don't then you get the default leading of 0.0. I provided a code sample for how to do this in my answer to a duplicate of this question here https://stackoverflow.com/a/10019378/1313863.

链接地址: http://www.djcxy.com/p/81900.html

上一篇: 使用核心文本动态更改视图高度

下一篇: 核心文本的CTFramesetterSuggestFrameSizeWithConstraints()每次都会返回不正确的大小