在iOS中检测UITextView中带属性的文本的轻击操作

129

我有一个显示NSAttributedStringUITextView。 这个字符串包含我想要点击的单词,当它们被点击时我会被回调以便执行某个操作。 我知道UITextView可以检测URL的点击并回调我的代理,但这些不是URL。

在我看来,随着iOS 7和TextKit的强大功能,现在应该是可能的。 但是我找不到任何例子,也不确定从哪里开始。

我了解现在可以在字符串中创建自定义属性(尽管我尚未这样做),也许这些属性将有助于检测是否已经点击了其中一个单词? 无论如何,我仍然不知道如何拦截该点击并检测点击发生在哪个单词上。

请注意,不需要兼容iOS 6。


注意:在iOS 10及以上版本中,请使用NSAttributedString.Key.link属性。请参见我的答案 - 不过,在那之前,似乎你必须采用这里接受的答案。 - Arafangion
12个回答

1
这个可能适用于在TextView中使用短链接、多链接。它在iOS 6、7、8上运行良好。
- (void)tappedTextView:(UITapGestureRecognizer *)tapGesture {
    if (tapGesture.state != UIGestureRecognizerStateEnded) {
        return;
    }
    UITextView *textView = (UITextView *)tapGesture.view;
    CGPoint tapLocation = [tapGesture locationInView:textView];

    NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink|NSTextCheckingTypePhoneNumber
                                                           error:nil];
    NSArray* resultString = [detector matchesInString:self.txtMessage.text options:NSMatchingReportProgress range:NSMakeRange(0, [self.txtMessage.text length])];
    BOOL isContainLink = resultString.count > 0;

    if (isContainLink) {
        for (NSTextCheckingResult* result in  resultString) {
            CGRect linkPosition = [self frameOfTextRange:result.range inTextView:self.txtMessage];

            if(CGRectContainsPoint(linkPosition, tapLocation) == 1){
                if (result.resultType == NSTextCheckingTypePhoneNumber) {
                    NSString *phoneNumber = [@"telprompt://" stringByAppendingString:result.phoneNumber];
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
                }
                else if (result.resultType == NSTextCheckingTypeLink) {
                    [[UIApplication sharedApplication] openURL:result.URL];
                }
            }
        }
    }
}

 - (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView
{
    UITextPosition *beginning = textView.beginningOfDocument;
    UITextPosition *start = [textView positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textView positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textView textRangeFromPosition:start toPosition:end];
    CGRect firstRect = [textView firstRectForRange:textRange];
    CGRect newRect = [textView convertRect:firstRect fromView:textView.textInputView];
    return newRect;
}

在iOS 9中,通过轻拍手势检测连续的轻拍无法正常工作。 - Dheeraj Jami

1
这在iOS 10中已经改变。在iOS 10中,您可以使用.link属性,一切都可以正常工作。
无需自定义属性、点击手势识别器或任何其他东西。它就像一个普通的URL一样工作。
为此,不要将URL添加到NSMutableAttributedString中,而是添加您想要称呼URL的内容(例如,“cats”去维基百科页面),然后添加标准属性NSAttributedString.Key.link (我在这里使用Swift),其中包含目标URL的NSURL。
参考: https://medium.com/real-solutions-artificial-intelligence/create-clickable-links-with-nsmutableattributedstring-12b6661a357d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接