CTFramesetterSuggestFrameSizeWithConstraints иногда возвращает неправильный размер?

В приведенном ниже коде CTFramesetterSuggestFrameSizeWithConstraints иногда возвращает CGSize с высотой, которая недостаточно велика, чтобы содержать весь текст, который передается в нее. Я посмотрел этот ответ. Но в моем случае ширина текстового поля должна быть постоянной. Есть ли другой/лучший способ определить правильную высоту для моей атрибутной строки? Спасибо!

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString);
CGSize tmpSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(self.view.bounds.size.width, CGFLOAT_MAX), NULL); 
CGSize textBoxSize = CGSizeMake((int)tmpSize.width + 1, (int)tmpSize.height + 1);

Ответ 1

CTFramesetterSuggestFrameSizeWithConstraints(). Некоторое время назад я подал ошибку. Ваша альтернатива - использовать CTFramesetterCreateFrame() с достаточно высоким уровнем. Затем вы можете измерить прямоугольник CTFrame, который вы вернетесь. Обратите внимание, что вы не можете использовать CGFLOAT_MAX для высоты, так как CoreText использует перевернутую систему координат с iPhone и найдет текст в верхней части окна. Это означает, что если вы используете CGFLOAT_MAX, у вас не будет достаточной точности, чтобы фактически рассказать высоту окна. Я рекомендую использовать что-то вроде 10 000 в качестве высоты, так как оно на 10 раз выше самого экрана и при этом дает достаточную точность для полученного прямоугольника. Если вам нужно выложить еще более высокий текст, вы можете сделать это несколько раз для каждой части текста (вы можете запросить CTFrameRef для диапазона в исходной строке, которую он мог выложить).

Ответ 2

CTFramesetterSuggestFrameSizeWithConstraints работает правильно. Причина, по которой вы получаете слишком короткую высоту, связана с тем, что в стиле абзаца по умолчанию используется привязанная строка. Если вы не прикрепляете стиль абзаца к строке, то CoreText возвращает высоту, необходимую для визуализации текста, но без пробела между строками. Это потребовало меня навсегда выяснить. Ничто в документации не говорит об этом. Я просто заметил, что мои высоты были короткими на сумму, равную (количество строк x, ожидаемое впереди). Чтобы получить результат роста, вы ожидаете, что вы можете использовать следующий код:

NSString  *text = @"This\nis\nsome\nmulti-line\nsample\ntext."
UIFont    *uiFont = [UIFont fontWithName:@"Helvetica" size:17.0];
CTFontRef ctFont = CTFontCreateWithName((CFStringRef) uiFont.fontName, uiFont.pointSize, NULL);

//  When you create an attributed string the default paragraph style has a leading 
//  of 0.0. Create a paragraph style that will set the line adjustment equal to
//  the leading value of the font.
CGFloat leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender;
CTParagraphStyleSetting paragraphSettings[1] = { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &leading };

CTParagraphStyleRef  paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
CFRange textRange = CFRangeMake(0, text.length);

//  Create an empty mutable string big enough to hold our test
CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, text.length);

//  Inject our text into it
CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) text);

//  Apply our font and line spacing attributes over the span
CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(string);
CFRange fitRange;

CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, bounds, &fitRange);

CFRelease(framesetter);
CFRelease(string);

Ответ 3

Спасибо Крису ДеСальво за отличный ответ! Наконец закончилось 16 часов отладки. Мне пришлось немного разобраться в синтаксисе Swift 3. Итак, поделитесь версией Swift 3 с настройкой стиля абзаца.

let leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = leading      
mutableAttributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: textRange)

Ответ 4

Наконец-то выясню... Когда используется CTFramesetterSuggestFrameSizeWithConstraints, возвращающий CGSize для рисования текста, размер считается недостаточно большим (иногда) для всего текста, поэтому последняя строка не нарисована. Я просто добавляю 1 к size.height для return, похоже, сейчас.

Что-то вроде этого:

suggestSize = CGSizeMake (предложеноSize.width, suggestSize.height + 1);