在 UITextView 中获取 link 的文本范围

Get text range of link in UITextView

我有一个包含 link 和一些其他文本的 UITextView。 link 检测已启用并正常工作 (iOS8)。但是,我在 textView 中找不到 link 的范围。

想法是扫描文本(在 link 检测完成后)并将 link 预加载到网络视图中,这样当用户点击某处的元素时,网络视图可以显示自己。

如何在 UITextView 中获取检测到的 link 范围?

如果您打算执行类似 Twitter 在推文中打开 links 的方式,请执行以下操作:

  1. UITextView 的委托设置为视图控制器。
  2. 在您的视图控制器中实施 UITextViewDelegate 方法 textView:shouldInteractWithURL:inRange:。当用户在文本视图中选择 link 时将调用此方法。在方法中,你会想要return NO。但是,在返回 NO 之前,您应该创建一个具有 Web 视图的新视图控制器,并使用作为参数传入的 URL 加载 Web 视图。

这不会像您提到的那样进行预加载,但我不确定您这样做是出于特定原因(例如您希望网络视图与文本视图一起显示)还是您想要这样做只是因为你认为一旦用户点击 link.

会有性能优势

一种方法是使用 enumerateAttribute:inRange:options:usingBlock:,在我的例子中 attr[yourTextView attributedText]

__block NSMutableDictionary *ranges = [[NSMutableDictionary alloc] init];
[attr enumerateAttribute:NSLinkAttributeName
                 inRange:NSMakeRange(0, [attr length])
                 options:0
              usingBlock:^(id value, NSRange range, BOOL *stop) {
    NSLog(@"Attribute: %@, %@", value, NSStringFromRange(range));
                  if (value)
                      [ranges setObject:value forKey:[NSValue valueWithRange:range]];
}];
NSLog(@"Ranges: %@", ranges);

我也保留了范围,以防万一,但是您可以使用 NSArray 和所有不同的 link 而不是 NSDictionary.

编辑:
根据您的评论,我可以假设您提到的 link 是因为 NSDataDetector。简而言之,它会从 NSString 中检测是否存在类似“http://www.randomSite.com”的内容。您可以阅读 NSDataDetector 以获取更多信息(它可以检测 phone 号码、邮件地址等),UITextView 通常会默认检测一些。 所以 NSAttributedString 可能不包含 NSLinkAttributeName 属性。

所以变通(这一次,我只保留了 link,但我想如果你也想要像以前的解决方案那样的范围,你知道该怎么做):

NSString *stringWithNSDataDetector = [yourTextView text];
NSError *error = nil;
NSDataDetector * dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink
                                                                error:&error];
//Check if (error) before
__block NSMutableArray *allMatches = [[NSMutableArray alloc] init];
[dataDetector enumerateMatchesInString:stringWithNSDataDetector
                           options:0
                             range:NSMakeRange(0, [stringWithNSDataDetector length])
                        usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop)
{
    if ([match resultType] == NSTextCheckingTypeLink)
        [allMatches addObject:[match URL]];
}];