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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:30:30