UILabel 接触点处的字符索引 [英] Character index at touch point for UILabel

查看:10
本文介绍了UILabel 接触点处的字符索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

For a UILabel, I'd like to find out which character index is at specific point received from a touch event. I'd like to solve this problem for iOS 7 using Text Kit.

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

Since UILabel doesn't provide access to its NSLayoutManager, I created my own based on UILabel's configuration like this:

- (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: (要点).

The code above is in a UILabel subclass with a UITapGestureRecognizer configured to call textTapped: (Gist).

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

The resulting character index makes sense (increases when tapping from left to right), but is not correct (the last character is reached at roughly half the width of the label). It looks like maybe the font size or text container size is not configured properly, but can't find the problem.

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

I'd really like to keep my class a subclass of UILabel instead of using UITextView. Has anyone solved this problem for UILabel?

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

Update: I spent a DTS ticket on this question and the Apple engineer recommended to override UILabel's drawTextInRect: with an implementation that uses my own layout manager, similar to this code snippet:

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

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

I think it would be a lot of work to keep my own layout manager in sync with the label's settings, so I'll probably go with UITextView despite my preference for UILabel.

更新 2: 毕竟我决定使用 UITextView.所有这些的目的是检测嵌入在文本中的链接的点击.我尝试使用 NSLinkAttributeName,但此设置在快速点击链接时不会触发委托回调.相反,您必须按下链接一段时间——非常烦人.所以我创建了没有这个问题的 CCHLinkTextView.

Update 2: I decided to use UITextView after all. The purpose of all this was to detect taps on links embedded in the text. I tried to use NSLinkAttributeName, but this setup didn't trigger the delegate callback when tapping a link quickly. Instead, you have to press the link for a certain amount of time – very annoying. So I created CCHLinkTextView that doesn't have this problem.

推荐答案

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

I played around with the solution of Alexey Ishkov. Finally i got a solution! Use this code snippet in your UITapGestureRecognizer selector:

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];

希望这会帮助一些人!

这篇关于UILabel 接触点处的字符索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆