iOS 手势冲突

手势冲突处理

  • 1、自定义手势优先级
  • 2、阻止手势向响应链传递执行
  • 3、实现协议方法 `UIGestureRecognizerDelegate` 控制手势冲突
  • 4、自定义手势

手势冲突主要的三种解决思路:

  • 设置手势优先级 requireGestureRecognizerToFail:
  • 阻止手势向事件传递链执行 cancelsTouchesInViewdelaysTouchesBegan
  • 实现协议方法 UIGestureRecognizerDelegate
  • (自定义手势)重写父类中的个别方法 @interface UIGestureRecognizer (UIGestureRecognizerProtected)

1、自定义手势优先级

场景一:
自定义多手势冲突。例如我们设置的单次点击、双击和三次点击手势,需要设置优先识别三击手势,识别失败后再识别双击手势;同理,双击手势识别失败后再识别单击手势。

    /// 自定义多手势冲突
    func test_1() {
        let oneGes = UITapGestureRecognizer(target: self, action: #selector(oneTap(tapGes:)))
        oneGes.numberOfTapsRequired = 1
        self.scrollVeiw.addGestureRecognizer(oneGes)
        
        let twoGes = UITapGestureRecognizer(target: self, action: #selector(twoTap(tapGes:)))
        twoGes.numberOfTapsRequired = 2
        self.scrollVeiw.addGestureRecognizer(twoGes)
        
        let threeGes = UITapGestureRecognizer(target: self, action: #selector(threeTap(tapGes:)))
        threeGes.numberOfTapsRequired = 3
        self.scrollVeiw.addGestureRecognizer(threeGes)
        // 优先级设置
        oneGes.require(toFail: twoGes)
        twoGes.require(toFail: threeGes)
    }
    @objc func oneTap(tapGes: UITapGestureRecognizer) {
        print("=================> oneTap")
    }
    @objc func twoTap(tapGes: UITapGestureRecognizer) {
        print("=================> twoTap")
    }
    @objc func threeTap(tapGes: UITapGestureRecognizer) {
        print("=================> threeTap")
    }

2、阻止手势向响应链传递执行

当自定义手势和系统手势冲突,可以使用手势的两个属性:cancelsTouchesInViewdelaysTouchesBegan进行处理。
例如:页面添加自定义手势 UIPanGestureRecognizer,与页面上的系统手势 touchesMoved(_ touches: Set, with event: UIEvent?) 回调方法冲突,可利用该属性屏蔽掉系统手势。

  • cancelsTouchesInView(是否取消向事件响应链传递):
    默认 YES,自定义的手势响应后,系统手势不再响应,但自定义手势识别前,会先执行系统手势。
    设置为 NO 后,自定义手势和系统手势会同时识别响应。
  • delaysTouchesBegan(延迟响应链的识别):
    默认 NO,先执行响应链中的方法(系统方法),识别到自定义手势后,不再执行系统方法。
    设置为 YES 后,优先识别自定义手势,当自定义手势识别失败后才会响应系统方法

屏蔽掉系统方法,我们只需要将属性 delaysTouchesBegan 设置为 YES 即可:

    // MARK: - 阻止手势向事件传递链传递
    func test_2() {
        let panGes = UIPanGestureRecognizer(target: self, action: #selector(panGestureAction(panGes:)))
        // 阻止手势向事件传递链执行 默认是 YES
        // panGes.cancelsTouchesInView = false
        // 延迟手势向事件传递链执行 默认是 NO
        panGes.delaysTouchesBegan = true
        self.view.addGestureRecognizer(panGes)
    }
    @objc func panGestureAction(panGes: UIPanGestureRecognizer) {
        let point = panGes.location(in: self.view)
        print("********************")
        print("W ==> \(point.x)")
        print("H ==> \(point.y)")
    }
    override func touchesMoved(_ touches: Set, with event: UIEvent?) {
        let point = touches.first?.location(in: self.view)
        print("=====================")
        print("W ==> \(String(describing: point?.x))")
        print("H ==> \(String(describing: point?.y))")
    }

3、实现协议方法 UIGestureRecognizerDelegate 控制手势冲突

常用的是第二个协议方法 gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer:

//手指触摸屏幕后回调的方法,返回NO则不再进行手势识别,方法触发等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
//开始进行手势识别时调用的方法,返回NO则结束,不再触发手势
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
//是否支持多时候触发,返回YES,则可以多个手势一起触发方法,返回NO则为互斥
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
//下面这个两个方法也是用来控制手势的互斥执行的
//这个方法返回YES,第一个手势和第二个互斥时,第一个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
//这个方法返回YES,第一个和第二个互斥时,第二个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

4、自定义手势

系统提供给我们的手势可以满足绝大多数的业务场景需求,对于特殊情况,可能需要用到自定义的手势。
继承 UIGestureRecognizer ,并重写以下方法:

    override func reset() {
        super.reset()
        state = .possible
    }
    override func touchesBegan(_ touches: Set, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        state = .began
    }
    override func touchesMoved(_ touches: Set, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
    }
    override func touchesEnded(_ touches: Set, with event: UIEvent) {
        super.touchesEnded(touches, with: event)
        state = .ended
    }
    override func touchesCancelled(_ touches: Set, with event: UIEvent) {
        super.touchesCancelled(touches, with: event)
        state = .changed
    }

根据其它博客内容提示,如需修改手势的 state 属性,需要引入 import UIKit.UIGestureRecognizerSubclass,但根据实测,未引入也不会报错。

你可能感兴趣的:(iOS)