objective-c - UILabel 触摸点的字符索引

标签 objective-c ios7 textkit

对于 UILabel,我想找出在特定点从触摸事件接收到的字符索引。我想使用 Text Kit 为 iOS 7 解决这个问题。

由于 UILabel 不提供对其 NSLayoutManager 的访问,因此我基于 UILabel 的配置创建了我自己的,如下所示:

- (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 子类中,带有配置为调用 textTapped: ( Gist ) 的 UITapGestureRecognizer

生成的字符索引有意义(从左向右点击时增加),但不正确(最后一个字符大约达到标签宽度的一半)。看起来可能是字体大小或文本容器大小配置不正确,但找不到问题。

我真的很想让我的类成为 UILabel 的子类,而不是使用 UITextView。有没有人为 UILabel 解决了这个问题?

更新:我在这个问题上花了一张 DTS 票,Apple 工程师建议用一个实现覆盖 UILabeldrawTextInRect:使用我自己的布局管理器,类似于此代码片段:

- (void)drawTextInRect:(CGRect)rect 
{
    [yourLayoutManager drawGlyphsForGlyphRange:NSMakeRange(0, yourTextStorage.length) atPoint:CGPointMake(0, 0)];
}

我认为让我自己的布局管理器与标签的设置保持同步需要做很多工作,所以我可能会使用 UITextView 尽管我更喜欢 UILabel.

更新 2:毕竟我决定使用 UITextView。所有这一切的目的是检测对文本中嵌入的链接的点击。我尝试使用 NSLinkAttributeName,但此设置在快速点击链接时不会触发委托(delegate)回调。取而代之的是,你必须按链接一段时间——这很烦人。所以我创建了CCHLinkTextView没有这个问题。

最佳答案

我试过 Alexey Ishkov 的解决方案。最后我得到了解决方案! 在您的 UITapGestureRecognizer 选择器中使用此代码片段:

UILabel *textLabel = (UILabel *)recognizer.view;
CGPoint tapLocation = [recognizer locationInView:textLabel];

// init text storage
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:textLabel.attributedText];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];

// init text container
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(textLabel.frame.size.width, textLabel.frame.size.height+100) ];
textContainer.lineFragmentPadding  = 0;
textContainer.maximumNumberOfLines = textLabel.numberOfLines;
textContainer.lineBreakMode        = textLabel.lineBreakMode;

[layoutManager addTextContainer:textContainer];

NSUInteger characterIndex = [layoutManager characterIndexForPoint:tapLocation
                                inTextContainer:textContainer
                                fractionOfDistanceBetweenInsertionPoints:NULL];

希望这会帮助一些人!

关于objective-c - UILabel 触摸点的字符索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21349725/

相关文章:

ios - 是否可以将 iOS 7 UIViewController 转换(特别是交互)与 subview Controller 一起使用?

iOS全文编辑器实现示例

ios - 如何使用 Text Kit 构建像 Medium iOS 应用程序这样的富 TextView ?

ios - 使用 Text Kit 将 UITextFields 与 UITextView 进行插值?

iphone - Objective C iPhone 开发,保存和检索 NSMutableArray

iphone - IOS 7 - 添加覆盖崩溃应用程序

ios - 将功能绑定(bind)到键盘中的 "Search"按钮

ios - iOS 6 和 iOS 7 在模拟器中的显示屏幕不同

ios - 具有按住 Action 和释放 Action 的 UIButton

objective-c - 使用 NSSearchField 时,辅助 NSTableView 失去焦点并且不会同时更新