Как получить реальную высоту текста, нарисованного на CTFrame
У меня есть определенное количество текста, который заполняет некоторые CTFrame
(больше одного). Чтобы создать все фреймы (по одному для каждой страницы), я заполняю один фрейм, получая текст, который не помещается в фрейм, используя CTFrameGetVisibleStringRange
и повторять этот процесс, пока весь текст не будет обработан.
На всех фреймах, кроме последнего, текст занимает одинаковую высоту страницы. На последнем кадре я хотел бы знать реальную высоту, занимаемую текстом, чтобы знать, где я мог бы начать рисовать больше текста.
Есть какой-либо способ сделать это?
ОБНОВИТЬ
Как и просили комментарии, вот мое решение, используя предложение @omz:
Я использую ARC в моем проекте:
CTFrameRef locCTFrame = (__bridge CTFrameRef)ctFrame;
//Save CTLines
lines = (NSArray *) ((__bridge id)CTFrameGetLines(locCTFrame));
//Get line origins
CGPoint lOrigins[MAXLINESPERPAGE];
CTFrameGetLineOrigins(locCTFrame, CFRangeMake(0, 0), lOrigins);
CGFloat colHeight = self.frame.size.height;
//Save the amount of the height used by text
percentFull = ((colHeight - lOrigins[[lines count] - 1].y) / colHeight);
4 ответа
Вы можете получить начало строки последней строки в кадре с помощью CTFrameGetLineOrigins
или используйте CTFramesetterSuggestFrameSizeWithConstraints
функция, чтобы получить размер прямоугольной рамки для заданного диапазона. Последнее не сработает, если вы используете непрямоугольные пути для установки фактических кадров.
+ (CGSize)measureFrame:(CTFrameRef)frame
{
// 1. measure width
CFArrayRef lines = CTFrameGetLines(frame);
CFIndex numLines = CFArrayGetCount(lines);
CGFloat maxWidth = 0;
for(CFIndex index = 0; index < numLines; index++)
{
CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex(lines, index);
CGFloat ascent, descent, leading, width;
width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
if(width > maxWidth)
maxWidth = width;
}
// 2. measure height
CGFloat ascent, descent, leading;
CTLineGetTypographicBounds((CTLineRef) CFArrayGetValueAtIndex(lines, 0), &ascent, &descent, &leading);
CGFloat firstLineHeight = ascent + descent + leading;
CTLineGetTypographicBounds((CTLineRef) CFArrayGetValueAtIndex(lines, numLines - 1), &ascent, &descent, &leading);
CGFloat lastLineHeight = ascent + descent + leading;
CGPoint firstLineOrigin;
CTFrameGetLineOrigins(frame, CFRangeMake(0, 1), &firstLineOrigin);
CGPoint lastLineOrigin;
CTFrameGetLineOrigins(frame, CFRangeMake(numLines - 1, 1), &lastLineOrigin);
CGFloat textHeight = ABS(firstLineOrigin.y - lastLineOrigin.y) + firstLineHeight + lastLineHeight;
return CGSizeMake(maxWidth, textHeight);
}
Я думаю, что user1021430 прав, говоря, что высота рассчитана неправильно.
Чтобы получить правильную высоту, вам нужно получить верхнюю часть первой линии (начало координат + первое восхождение) и нижнюю часть последней строки (начало координат - спуск), а затем вычесть эти два и получить фактическую высоту.
CGSize
MeasureTextWithinFrame(
CTFrameRef frame)
{
CGSize textSize = CGSizeMake(0.0f, 0.0f);
CFArrayRef lines = CTFrameGetLines(frame);
CFIndex numLines = CFArrayGetCount(lines);
// if there is at least one line
if (numLines > 0) {
// measure width
for (CFIndex index = 0; index < numLines; index++) {
CTLineRef line = (CTLineRef) CFArrayGetValueAtIndex(lines, index);
CGFloat ascent, descent, leading, width;
width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
if (width > textSize.width)
textSize.width = width;
}
// measure height
CGFloat firstAscent, firstDescent, firstLeading;
CTLineGetTypographicBounds((CTLineRef) CFArrayGetValueAtIndex(lines, 0), &firstAscent, &firstDescent, &firstLeading);
CGPoint firstLineOrigin;
CTFrameGetLineOrigins(frame, CFRangeMake(0, 1), &firstLineOrigin);
CGFloat lastAscent, lastDescent, lastLeading;
CTLineGetTypographicBounds((CTLineRef) CFArrayGetValueAtIndex(lines, numLines - 1), &lastAscent, &lastDescent, &lastLeading);
CGPoint lastLineOrigin;
CTFrameGetLineOrigins(frame, CFRangeMake(numLines - 1, 1), &lastLineOrigin);
float top = firstLineOrigin.y + firstAscent;
float bottom = lastLineOrigin.y - lastDescent;
textSize.height = ABS(top - bottom);
}
return textSize;
}