对于一个 UILabel
,我想找出在触摸事件接收到的特定点处的字符索引。我想使用 Text Kit 解决 iOS 7 中的这个问题。
由于 UILabel 没有提供访问其 NSLayoutManager
的方法,因此我根据 UILabel
的配置创建了自己的 NSLayoutManager
,如下所示:
- (void)textTapped:(UITapGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint location = [recognizer locationInView:self];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size];
[layoutManager addTextContainer:textContainer];
textContainer.maximumNumberOfLines = self.numberOfLines;
textContainer.lineBreakMode = self.lineBreakMode;
NSUInteger characterIndex = [layoutManager characterIndexForPoint:location
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:NULL];
if (characterIndex < textStorage.length) {
NSRange range = NSMakeRange(characterIndex, 1);
NSString *value = [self.text substringWithRange:range];
NSLog(@"%@, %zd, %zd", value, range.location, range.length);
}
}
}
上述代码在一个UILabel子类中,配置了UITapGestureRecognizer来调用textTapped: (Gist)。
得到的字符索引是有意义的(从左到右点击时增加),但不正确(最后一个字符在标签宽度的大约一半处到达)。看起来可能字体大小或文本容器大小没有正确配置,但找不到问题所在。
我真的很想保持我的类是UILabel的子类,而不是使用UITextView。有人解决了这个UILabel的问题吗?
更新:我在这个问题上花了一个DTS票据,苹果工程师建议覆盖UILabel的drawTextInRect:方法,使用自己的布局管理器实现,类似于这段代码片段:
- (void)drawTextInRect:(CGRect)rect
{
[yourLayoutManager drawGlyphsForGlyphRange:NSMakeRange(0, yourTextStorage.length) atPoint:CGPointMake(0, 0)];
}
我认为保持自己的布局管理器与标签设置同步需要大量工作,因此尽管我更喜欢UILabel,但我可能会选择UITextView。
更新2:最终我决定使用UITextView。所有这些的目的是检测嵌入文本中的链接的点击。我尝试使用NSLinkAttributeName,但这种设置在快速点击链接时不会触发委托回调。相反,您必须按链接一段时间 - 非常烦人。所以我创建了CCHLinkTextView来解决这个问题。
textContainer.lineFragmentPadding = 0;
,在你的示例中缺失了,但在 @Alexey Ishkov 和 @Kai Burghardt 的答案中存在。我不必使用数字100来破解containerSize。 - koen