自定义XIB UITableViewCell中contentView交互开启时didSelectRowAt不触发问题
我之前也碰到过一模一样的坑!其实根本不是contentView.isUserInteractionEnabled = true和didSelectRowAt只能二选一的问题,大概率是你的UIButton把cell的点击事件给拦截了,或者有几个容易忽略的配置没做好。下面给你几个实用的排查和解决方向:
检查UIButton的点击范围与事件优先级
UIButton默认是开启用户交互的,如果它的frame覆盖了整个cell的contentView,那么点击事件会被按钮直接吃掉,cell的选中事件自然触发不了。- 如果按钮只是cell的一部分:那完全没问题,点击按钮外的区域就能触发
didSelectRowAt; - 如果按钮必须占满整个cell:那你可以在按钮的点击事件里手动处理cell选中逻辑,比如获取当前cell的
indexPath,然后调用tableView的选中逻辑,或者用闭包把事件传递到控制器。
- 如果按钮只是cell的一部分:那完全没问题,点击按钮外的区域就能触发
确保UITableViewCell本身的用户交互开启
有时候会不小心把cell本身的isUserInteractionEnabled设为false,哪怕contentView开了也没用。你可以在cell的awakeFromNib或者配置cell的代码里加上:self.isUserInteractionEnabled = true检查UITableView的
allowsSelection属性
这个超级容易被忽略!如果你的tableView设置了allowsSelection = false,那不管cell怎么配置,didSelectRowAt都不会触发。赶紧确认一下:tableView.allowsSelection = true自定义事件传递逻辑(如果需要同时触发按钮和cell选中)
如果你既想让按钮响应点击,又想触发cell的didSelectRowAt,可以重写按钮的hitTest方法,在按钮接收点击的同时,手动触发cell的选中状态并传递事件:class CustomInteractiveButton: UIButton { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let resultView = super.hitTest(point, with: event) // 找到当前所在的cell if let cell = self.findSuperview(ofType: UITableViewCell.self) { cell.setSelected(true, animated: true) // 这里可以通过代理/闭包把选中事件传递给控制器,模拟didSelectRowAt的逻辑 } return resultView } // 辅助方法:查找指定类型的父视图 private func findSuperview<T: UIView>(ofType type: T.Type) -> T? { var currentView = superview while currentView != nil { if let targetView = currentView as? T { return targetView } currentView = currentView?.superview } return nil } }
总结一下:contentView.isUserInteractionEnabled = true是cell正常交互的基础,完全不需要关闭它。问题的核心在于事件传递的优先级或者配置遗漏,按照上面的步骤排查,肯定能解决你的问题!
内容的提问来源于stack exchange,提问作者dre_84w934

