views:

691

answers:

2

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

A: 

What do you mean shorter than expected? What are you expecting?

You mean it draws wrong? Then post your drawing code..

mustISignUp
My question isn't about drawing. It's about the size that the frame setter returns. I've updated my question with some further info.
nsapplication
I know that the question isn't about drawing, thanks. In the catastrophic code you post a link to the OP is just drawing the text wrong, and jumps to the conclusion that CTFramesetterSuggestFrameSizeWithConstraints() has returned an incorrect height, which it hasn't, and won't.
mustISignUp
mustISignUp... would you be willing to enlighten us on the proper way? I am needing CTFramesetterSuggestFrameSizeWithConstraints as well and can find no good examples or documentation that illustrate how.
Stephen Tallent
@Stephen: can you give me an example that you think doesn't work? As far as the original post is concerned the result may or may not be accurate - we have no way of knowing as the poster didn't post the actual code (what font is being used, what value is 'rect', etc.). Considering we dont know the font, font-size, string, or set-width, 133 x 16 seems perfectly reasonable, no?
mustISignUp
Sure. I'll post some code a bit later. Been a bit busy with some rain here in TN. Regardless, even the code in the original shows the problem/misunderstanding we are having. The frame size returned by this method in theory should be able to be used by the same framesetters CreateFrame method. It should account for the attributed strings details that was used to create the framesetter. It doesnt appear to. In that when you use a width narrow enough to force the string to wrap, the height returned isn't enough to show all the lines. Take the OP code, change it to a longer sentence and draw...
Stephen Tallent
or wait for a bit and i will take the OP code and put it in a drawRect for you.
Stephen Tallent
I'll give it a go, good luck with that rain.
mustISignUp
ok, it's wrong. Seems to me to be consistently 'fontPtSize' too short, which i guess is paddidng at the top and bottom.
mustISignUp
Excellent. Without any good examples i couldn't be sure i just wasn't doing something wrong. Interestingly, Mo's above example also gave me a reliable workaround. In his example, if i take wrongHeight variable he defines and add it to the height returned by SuggestSize it appears to work reliably, too. Many thanks for helping look into this.
Stephen Tallent
A: 

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.

Mo
Many thanks, Mo. This helped me find what appears to be a reliable workaround for the SuggestSize when doing multiline labels.
Stephen Tallent
Glad I could help. Did you check if I was right about the `wrongHeight`? I want to file a bug report.PS. thanks gf.
Mo