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

查看:167
本文介绍了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).

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

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工程师建议使用我自己的布局管理器覆盖 UILabel drawTextInRect: ,类似于以下代码片段:

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天全站免登陆