iOS开发:触发UIPinchGestureRecognizer时如何取消UIPanGestureRecognizer?
解决UIPan与UIPinch手势的优先级冲突问题
先分析你第一个方案的核心错误
你写的shouldRequireFailOf逻辑完全搞反了:
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer == myPanGestureRecognizer && otherGestureRecognizer == myPinchGestureRecognizer { return true } return false }
这段代码的实际作用是:平移手势必须等捏合手势识别失败后,才能被触发。这就导致只要用户用双指触发捏合手势,平移就永远不会工作;就算单指操作,也可能因为捏合手势的失败判定延迟,导致平移响应异常,最终出现你看到的「平移直接被禁用」的问题。
你要的是「捏合触发时平移失效」,正确的逻辑应该是让捏合手势优先被识别,平移手势仅在捏合未触发时工作。
最省心的解决方案:直接限制触摸数量
不需要写任何delegate方法,给两个手势设置触摸数量的上下限,系统会自动区分操作:
// 平移手势仅响应单指操作 myPanGestureRecognizer.minimumNumberOfTouches = 1 myPanGestureRecognizer.maximumNumberOfTouches = 1 // 捏合手势仅响应双指操作 myPinchGestureRecognizer.minimumNumberOfTouches = 2 myPinchGestureRecognizer.maximumNumberOfTouches = 2
单指滑动只会触发平移,双指捏合只会触发捏合,完全不会出现冲突,也能从根源避免你第二个方案里的「手势状态异常」问题——因为捏合手势在触摸数量低于2时,会自动切换到.ended状态。
若必须用Delegate调整优先级
可以用shouldBeRequiredToFailBy方法明确优先级:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { // 平移手势必须等捏合手势失败后,才能被触发 return gestureRecognizer == myPanGestureRecognizer && otherGestureRecognizer == myPinchGestureRecognizer }
或者用shouldRequireFailureOf反向配置:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool { // 捏合手势无需等待平移手势失败,直接优先触发 return gestureRecognizer == myPinchGestureRecognizer && otherGestureRecognizer == myPanGestureRecognizer }
记得给两个手势都设置delegate = self,否则不会生效。
解决你第二个方案的状态异常问题
如果坚持用触摸数量判断的方式,必须在手势处理中补全所有状态的处理,避免状态滞留:
@objc func didPinch(_ sender: UIPinchGestureRecognizer) { switch sender.state { case .began: guard sender.numberOfTouches == 2 else { sender.state = .cancelled return } // 捏合开始逻辑 case .changed: guard sender.numberOfTouches == 2 else { sender.state = .ended return } // 捏合变化逻辑 case .ended, .cancelled, .failed: // 捏合结束/取消逻辑 default: break } }
当触摸数量不符合要求时,手动将手势状态置为.ended或.cancelled,强制结束手势流程。
内容的提问来源于stack exchange,提问作者cleanrun
相关产品推荐
相关产品推荐

