iOS:为父视图添加Tap手势后,UIControl子类触摸事件不触发
问题原因与解决方案
当父视图添加UITapGestureRecognizer后,默认情况下手势识别器会拦截触摸事件,取消事件向子视图层级的传递(cancelsTouchesInView默认值为true),导致你的CustomControl无法接收到触摸事件。
下面提供两种可行的解决方法:
方法一:允许事件继续传递给子视图
修改手势识别器的cancelsTouchesInView属性为false,这样手势识别完成后,触摸事件仍会传递给子视图的UIControl,两者的事件都会被触发:
override func viewDidLoad() { super.viewDidLoad() customControl.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapOnView(_:))) tapGesture.cancelsTouchesInView = false // 关键设置 view.addGestureRecognizer(tapGesture) }
方法二:让手势跳过CustomControl的触摸
通过手势代理,判断触摸点是否落在CustomControl范围内,若是则不让手势处理该触摸,确保CustomControl的事件优先响应:
- 让
ViewController遵循UIGestureRecognizerDelegate协议 - 设置手势的代理为当前控制器
- 实现
shouldReceiveTouch方法过滤触摸事件
class ViewController: UIViewController, UIGestureRecognizerDelegate { @IBOutlet weak var customControl: CustomControl! override func viewDidLoad() { super.viewDidLoad() customControl.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapOnView(_:))) tapGesture.delegate = self // 设置代理 view.addGestureRecognizer(tapGesture) } // 过滤CustomControl范围内的触摸 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return !touch.view!.isDescendant(of: customControl) } @objc func didTap(_ sender: Any) { print("CustomControl 被点击") } @objc func didTapOnView(_ sender: UITapGestureRecognizer) { print("父视图被点击") } }
两种方法的区别
- 方法一:点击
CustomControl时,同时触发它的touchUpInside事件和父视图的Tap手势 - 方法二:点击
CustomControl时,仅触发它自己的事件,父视图手势不响应;点击其他区域时触发父视图手势
内容的提问来源于stack exchange,提问作者Summit
相关产品推荐
相关产品推荐

