Как получить реальную высоту текста, нарисованного на 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);
}

Использование CTLineGetTypographicBounds,

Я думаю, что 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;
}
Другие вопросы по тегам