You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让UITableView中的UITextView可点击,解决单元格点击异常问题

问题原因

UITextView的交互优先级高于单元格,默认会拦截所有触摸事件,不会向下传递到UITableViewCell的响应链。你开启的selectable和userInteractionEnabled是用于让UITextView本身响应选中文本、点击链接、编辑等交互,反而会强化其事件拦截优先级,无法解决单元格点击被拦截的问题。

解决方案

场景1:仅用UITextView展示富文本,不需要任何交互

直接关闭UITextView的用户交互即可,所有触摸事件会自动透传到下层单元格:

// Swift
textView.isUserInteractionEnabled = false
// Objective-C
textView.userInteractionEnabled = NO;

场景2:需要保留UITextView的选中文本、点击链接等交互,同时支持点击空白区域触发单元格点击

有两种常用实现方式可选:

方案A:添加点击手势手动触发单元格选中

给UITextView添加点击手势,判断点击位置不是链接/选中区域时,手动调用单元格的选中代理方法:

  1. 配置手势
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTextViewTap(_:)))
tap.cancelsTouchesInView = false
tap.numberOfTapsRequired = 1
tap.delegate = self
textView.addGestureRecognizer(tap)
  1. 实现手势响应逻辑
@objc private func handleTextViewTap(_ gesture: UITapGestureRecognizer) {
    let location = gesture.location(in: textView)
    // 点击到链接时不触发单元格点击
    if let pos = textView.closestPosition(to: location),
       let linkAttr = textView.textStyling(at: pos, in: .forward)?[.link],
       linkAttr != nil {
        return
    }
    // 找到textView所在的单元格
    var currentView: UIView? = textView
    while currentView != nil {
        if let cell = currentView as? UITableViewCell,
           let indexPath = tableView.indexPath(for: cell) {
            tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
            break
        }
        currentView = currentView?.superview
    }
}
  1. 实现手势代理避免和内置手势冲突
extension YourViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

方案B:自定义UITextView透传非必要事件

重写UITextView的hitTest方法,不需要textView响应的事件直接透传给父视图:

class PassThroughTextView: UITextView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // 点击到链接/处于编辑/选中状态时,由textView响应
        if let pos = closestPosition(to: point),
           let linkAttr = textStyling(at: pos, in: .forward)?[.link],
           linkAttr != nil || isFirstResponder || isSelected {
            return super.hitTest(point, with: event)
        }
        // 其余事件透传
        return nil
    }
}

后续把你用到的UITextView的类指定为PassThroughTextView即可。

注意事项

如果需要支持UITextView编辑功能,要在逻辑中额外判断isFirstResponder状态,编辑状态下优先由textView响应所有事件,避免输入被打断。

内容的提问来源于stack exchange,提问作者tHatpart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:54:02