似乎有其他人有这个问题,但我还没有找到解决方案。我正在尝试使用突出显示的背景创建一个UILabel,就像OS X中桌面文件下面的标签一样,如下所示:
我决定使用CoreText来解决这个问题,我偶然发现了一个我似乎无法解决的错误:
在我的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有没有出现任何新信息?我为什么功能的值没有了,我感到茫然。
答案 0 :(得分:2)
我会做这样的事情来得到一条直线:
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);
我更喜欢在图像边界上使用印刷边界。我认为你需要提升,体面并领先获得起源。我也总是偏离帧原点,但你可能不需要。