CTFrameGetLineOrigins错误

似乎还有其他人有这个问题,但我还没有找到解决办法。 我正在尝试创建一个高亮背景的UILabel,与OS X中桌面文件下面的标签完全相同,如下所示:

OS X桌面文件标签

我决定用CoreText来解决这个问题,而且我偶然发现了一个我似乎无法解决的错误:

-drawRect方法

在我的UILabel的drawRect方法中,我使用CoreText将文本绘制到屏幕上,然后为绘制的每一行文本创建一个UIBezierPath。 (该标签永远不会超过两行)

CGContext context = UIGraphicsGetCurrentContext();
/* Flip coordinate plane */
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.bounds);

NSAttributedString *attributedText = [self attributedText]; /* [self attributedText] returns an NSAttributedString formatted with font, linebreak, and alignment. */

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attributedText length]), path, NULL);
CFArrayRef lines = CTFrameGetLines(frame);

CGPoint *lineOrigins = malloc(CFArrayGetCount(lines));
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), lineOrigins); //<------

/* Get frame for line 1 */
CTLineRef line1 = CFArrayGetValueAtIndex(lines, 0);
CGRect lineFrame = CTLineGetImageBounds(line1, context); 

CGPoint lineFrameOrigin = CGPointMake(lineOrigins[0].x, self.bounds.size.height - lineOrigins[0].y);//Coordinates flipped once again
lineFrame.origin = lineFrameOrigin;

UIBezierPath *linePath = [UIBezierPath bezierPathWithRoundedRect:lineFrame cornerRadius:0];

[self.path appendPath:linePath];
/* Repeat for line 2 */

CTFrameDraw(frame, context);//Draw the text.

在为每一行获得CGRect后,将它放入UIBezierPath中,然后通过-appendPath方法将其与其他行的路径合并。 从路径制作图层蒙版,并将标签的背景颜色更改为蓝色。

问题

奇怪的是,这是上面的代码的输出:

在这里输入图像描述

面具位于太远,我不知道为什么。 看起来CTFrameGetLineOrigins函数正在返回一个不正确的y值。

通过添加下面的代码行:

lineFrameOrigin.y -= self.font.leading / 2;

结果得到改善:

在这里输入图像描述

但是,它在y轴上似乎仍然过低。 我相信上面的这条线只是一个巧合,这个值恰好接近正确的y值。

无论如何,因为我知道这个问题之前已经被问过了,有没有其他方法可以实现这个目标? 这个奇怪的bug有没有新的信息? 我为什么函数的值被关闭了,我感到很惊讶。


我会做这样的事情来得到直线:

CTFrameRef frame;
CFArrayRef lines = CTFrameGetLines(frame);

CFIndex numLines = CFArrayGetCount(lines);

CTLineRef line1 = (CTLineRef)CFArrayGetValueAtIndex(lines, 0);

CGPoint *origins = (CGPoint *)malloc(numLines * sizeof(CGPoint));
CTFrameGetLineOrigins(self.ctFrame, CFRangeMake(0, 0), origins);

CGPoint origin = origins[0];
CGFloat ascent, descent, leading;

CTLineGetTypographicBounds(line1, &ascent, &descent, &leading);

CFRange lineRange = CTLineGetStringRange(line1);

CGFloat lineStart = CTLineGetOffsetForStringIndex(line1, lineRange.location, NULL);
CGFloat lineEnd   = CTLineGetOffsetForStringIndex(line1, CFRangeMaxRange(lineRange), NULL);

CGRect box = CGPathGetBoundingBox(CTFrameGetPath(frame));

CGFloat lineHeight = ascent + descent + leading;

CGFloat rectX = box.origin.x + origin.x + lineStart;
CGFloat rectY = box.origin.y + origin.y - lineHeight;

CGRect rectForLine = CGRectMake( rectX, rectY, lineEnd - lineStart, lineHeight);

我更喜欢在图像边界上获得印刷边界。 我认为你需要上升,体面和导致获得起源。 我也总是偏离帧起源,但你可能不需要。

链接地址: http://www.djcxy.com/p/14379.html

上一篇: CTFrameGetLineOrigins Bug

下一篇: Laying out individual glyphs with Core Text