在 iOS11 系统更新的推送之后,有大部分 iOS11 的用户反馈在 iOS11 的系统上 UITextView 的 link 很难点击打开。经过几番的测试和搜索终于几乎能稳定复现这个问题 —— UITextView 中的 link 难以点击。

由于历史原因,在 app 中一些复制、选择等操作的文本都是采用 UITextView 来实现的,然而这些 UITextView 是作为 UITableViewCell 的子视图。UITextView 作为复制、选择、高亮链接的控件还是不错的选择。在 iOS11 之后 UITextView 加入了新的交互操作 Drag & Drop,高亮的链接和 Attchement 在长按几毫秒之后可以拖拽,这个操作之后发现点击链接变的难点了。其实这个只是一个表象而已,经过之后的尝试发现,其实 UITextView 中的高亮链接不是之前所理解 轻触 打开而是 点击按压 打开。所以你会发现在 iOS11 之后需要一个明显的 点击并按压 的过程才能打开链接,只是在 iOS11 之后这个过程不是那么的明显而已。然而怎么实现链接 轻触 打开呢?

做了以下两种尝试:

  1. 利用响应链来帮助我们找到需要点击的区域
  2. 再 UITextView 上增加一个 tap (轻触)手势。通过手势的点击来获取本文信息

方案 1 实现有一个问题就是我们很难模拟出系统的 upinside 这样的点击状态,所以我们一旦 touch 到高亮的 link 就会马上响应方法,甚至在我们滑动的时候 touch 到也会响应该方法,用户体验不好。
具体的实现可以查看: https://stackoverflow.com/questions/36198299/uitextview-disable-selection-allow-links/44878203#44878203

方案 2 的实现是可以接受的,具体的实现过程:
在 tap 手势的方法中 通过locationInView 方法获取在 UITextView 的点击坐标,再 closestPositionToPoint 方法获取坐标对应的文本位置,再通过 textStylingAtPosition: inDirection 获取点击附近所包含的文本信息,判断这个文本信息的字典中是否含有 NSLinkAttributeName key 所对应的值,如果有说明是我们需要的 Attachment,取出他的值就是我们需要打开的 url。

最后讲一点,在 iOS11 之前,点击事件能穿透 UITextView 响应 tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 代理方法,当然,这里需要设置 UITextView 的 selectable = true 和 isUserInteractionEnabled = false。但是在 iOS11 之后不能响应该代理方法了。

源码的 examples: https://github.com/acumen1005/Examples