如何使用Core Text获取最后一个字符的矩形框

5
我有一个NSAttributedString字符串和要绘制的整个字符串矩形,我想获取最后一个字符的矩形,就像下面的图片一样。如何使用Core Text实现呢?
1个回答

5

具体使用CoreText,这里有一个应该可以工作的函数(代码中有一些注释解释了正在发生的事情):

- (CGRect)lastCharacterRectForAttributedString:(NSAttributedString *)attributedString drawingRect:(CGRect)drawingRect
{
    // Start by creating a CTFrameRef using the attributed string and rect.
    CTFrameRef textFrame = NULL;
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedString));
    CGPathRef drawingPath = CGPathCreateWithRect(drawingRect, NULL);
    textFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attributedString length]), drawingPath, NULL);
    CFRelease(framesetter);
    CFRelease(drawingPath);

    // Line origins can be obtained from the CTFrameRef. Get the final one.
    CGPoint finalLineOrigin;
    CFArrayRef lines = CTFrameGetLines(textFrame);
    if (CFArrayGetCount(lines) == 0) { // Safety check
        CFRelease(textFrame);
        return CGRectNull;
    }
    const CFIndex finalLineIdx = CFArrayGetCount(lines) - 1;
    CTFrameGetLineOrigins(textFrame, CFRangeMake(finalLineIdx, 1), &finalLineOrigin);

    // Get the glyph runs from the final line. Get the last glyph position from the final run.
    CGPoint glyphPosition;
    CFArrayRef runs = CTLineGetGlyphRuns(CFArrayGetValueAtIndex(lines, finalLineIdx));
    if (CFArrayGetCount(runs) == 0) { // Safety check
        CFRelease(textFrame);
        return CGRectNull;
    }
    CTRunRef finalRun = CFArrayGetValueAtIndex(runs, CFArrayGetCount(runs) - 1);
    if (CTRunGetGlyphCount(finalRun) == 0) { // Safety check
        CFRelease(textFrame);
        return CGRectNull;
    }
    const CFIndex lastGlyphIdx = CTRunGetGlyphCount(finalRun) - 1;
    CTRunGetPositions(finalRun, CFRangeMake(lastGlyphIdx, 1), &glyphPosition);

    // The bounding box of the glyph itself is extracted from the font.
    CGRect glyphBounds;
    CFDictionaryRef runAttributes = CTRunGetAttributes(finalRun);
    CTFontRef font = CFDictionaryGetValue(runAttributes, NSFontAttributeName);
    CGGlyph glyph;
    CTRunGetGlyphs(finalRun, CFRangeMake(lastGlyphIdx, 1), &glyph);
    CTFontGetBoundingRectsForGlyphs(font, kCTFontDefaultOrientation, &glyph, &glyphBounds, 1);

    // Option 1 - The rect you've drawn in your question isn't tight to the final character; it looks approximately the height of the line. If that's what you're after:
    CGRect lineBounds = CTLineGetBoundsWithOptions(CFArrayGetValueAtIndex(lines, finalLineIdx), 0);
    CGRect desiredRect = CGRectMake(
                                    CGRectGetMinX(drawingRect) + finalLineOrigin.x + glyphPosition.x + CGRectGetMinX(glyphBounds),
                                    CGRectGetMinY(drawingRect) + (CGRectGetHeight(drawingRect) - (finalLineOrigin.y + CGRectGetMaxY(lineBounds))),
                                    CGRectGetWidth(glyphBounds),
                                    CGRectGetHeight(lineBounds)
                                    );
    // Option 2 - If you want a rect that closely bounds the final character, use this:
    /*
    CGRect desiredRect = CGRectMake(
                                    CGRectGetMinX(drawingRect) + finalLineOrigin.x + glyphPosition.x + CGRectGetMinX(glyphBounds),
                                    CGRectGetMinY(drawingRect) + (CGRectGetHeight(drawingRect) - (finalLineOrigin.y + glyphPosition.y + CGRectGetMaxY(glyphBounds))),
                                    CGRectGetWidth(glyphBounds),
                                    CGRectGetHeight(glyphBounds)
                                    );
    */

    CFRelease(textFrame);

    return desiredRect;
}

嗨,@Stefan。我之前在这里发布过一个类似的问题,我认为它与这个问题密切相关。但是,我的问题不仅仅是想找到最后一个字母的边界框,而是要找到给定特定字体、大小和间距的一行字母的大小,并使用CoreText将它们均匀地分布在一行上(或者一个UILabel)。如果你有时间,请看一下那里。提前致谢。 - Unheilig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接