如何在UIPickerView中启用其子视图的点击手势响应
UIPickerView子视图点击无响应问题解决方案
核心问题解答
- UIPickerView本身不会主动拦截其子视图的点击事件,出现点击无响应是因为其内部复用Cell默认会关闭子视图交互,且UIPickerView自带的行选择手势优先级高于子视图的控件响应事件,导致事件被手势消费,无法传递到UITextView。
- 不需要重写完整的响应链相关方法,只需要调整事件传递优先级即可解决问题。
修复步骤
- 首先确认自定义行视图和内部UITextView的
isUserInteractionEnabled属性均设置为true,系统在复用UIPickerView行视图时会默认重置该属性为false,需要在自定义视图的layoutSubviews或者复用回调里重新赋值。 - 自定义UIPickerView子类,重写
hitTest(_:with:)方法调整事件传递逻辑,优先判断子视图是否需要响应事件:
class EventTransferPickerView: UIPickerView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // 遍历当前所有组件的选中行 for component in 0..<numberOfComponents { let currentRow = selectedRow(inComponent: component) guard let rowView = view(forRow: currentRow, forComponent: component) else { continue } // 转换坐标到行视图坐标系 let rowPoint = convert(point, to: rowView) // 点击位置落在当前行视图范围内时,优先查找行内可响应的子视图 if rowView.bounds.contains(rowPoint), let targetView = rowView.hitTest(rowPoint, with: event) { return targetView } } // 没有匹配的子视图时走默认逻辑 return super.hitTest(point, with: event) } }
- 不要在全局控制器内设置UITextView的代理,直接在自定义行视图内部成为对应UITextView的代理,避免视图复用时代理被覆盖,导致
textViewDidBeginEditing无法触发。
示例参考


内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

