CTLineGetStringRange 和 CTLineGetGlyphCount 返回的行中的字符数错误



我有一个应用程序,我使用CoreText绘制文本突出显示。它运行良好,除了当我尝试使用CTLineGetStringRange获取一行中的字符数时,它通常会给我一个比实际更大的数字。例如,在包含 156 个字符的行中,范围的长度为 164。 CTLineGetGlyphCount返回了相同的数字。

有人知道为什么会这样吗?我用来创建框架设置器的NSAttributedString使用与我的UITextView完全相同的字体。

这是我的代码:

// Build the attributed string from our text data and string attribute data
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:self.text attributes:self.attributes];    
// Create the Core Text framesetter using the attributed string
_framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString);
// Create the Core Text frame using our current view rect bounds
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
_frame =  CTFramesetterCreateFrame(_framesetter, CFRangeMake(0, 0), path.CGPath, NULL);
NSArray *lines = (__bridge NSArray *) CTFrameGetLines(_frame);
for (int i = 0; i < lines.count; i++) {
    CTLineRef line = (__bridge CTLineRef) [lines objectAtIndex:i];
    CFRange lineRange = CTLineGetStringRange(line);
    NSLog(@"lineRange: %ld, %ld", lineRange.location, lineRange.length);
    CFIndex glyphCount = CTLineGetGlyphCount(line);
    NSLog(@"glyphCount: %ld", glyphCount);
}

我的类是UIView的子类,它作为子视图添加到 UITextView 的子类的实例中。

编辑:这是我正在测试的示例字符串:

textView.text = @"Marvel's The Avengers is a 2012 American superhero film produced by Marvel Studios and distributed by Walt Disney Pictures, based on the Marvel Comics superhero team of the same name.";

在这种情况下,第一行包含
《漫威复仇者联盟》是一部2012年的美国超级英雄电影,由漫威影业制作,华特迪士尼影业发行,改编自137个字符长。但它给了我一个长度为 144 的线的范围。

但是,当我尝试使用以下文本时,结果有所不同:

textView.text = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";

现在第一行包含
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim ",长度为 142。但在这里它给了我长度为 142 的正确范围。

然后我尝试了另外几篇文本:

发短信:"阿斯加德洛基遇到了另一个,一个被称为Chitauri的外星种族的领袖。为了换取取Tesseract,一种潜力未知的强大能量来源,另一个人向洛基承诺一支Chitauri军队,他可以用它征服地球。
结果:"阿斯加德洛基遇到了另一个,一个被称为Chitauri的外星种族的领袖。作为取回泰瑟拉特的交换,一个长度为 145 的强大"
线范围长度:145

发短信:"史塔克和罗杰斯意识到,仅仅击败他们对洛基来说是不够的;他需要公开压倒他们,以证明自己是地球的统治者。
结果:"史塔克和罗杰斯意识到,仅仅击败他们对洛基来说是不够的;他需要公开压倒他们,以证明自己是统治者"长度为146。
线范围长度:149

因此,正如您所看到的,有时它是正确的,有时则不是。我找不到解释。

我根据这个答案中给出的提示解决了这个问题。

似乎因为UITextView继承自UIScrollView所以它的每条边缘都有一个 8 像素的内陷。这意味着我的内部UIView有一个比我的UITextView宽 16 像素的文本空间,有时这种差异意味着它可以在进入新行之前再容纳一个单词,这给出了行中的错误字符数。

因此,从视图宽度中减去 16 个像素为我解决了这个问题。

但是,这只是我解决方案的一部分。另一部分是从核心文本中的属性字符串中删除字距调整和连字:

CFAttributedStringSetAttribute(string, textRange, kCTKernAttributeName, (__bridge CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute(string, textRange, kCTLigatureAttributeName, (__bridge CFTypeRef)([NSNumber numberWithInt:0]));

现在线条完美契合。

最新更新