美文网首页iOSios基础知识
UIGestureRecognizerDelegate学习笔记

UIGestureRecognizerDelegate学习笔记

作者: Sniper_Zheng | 来源:发表于2017-10-28 22:38 被阅读795次

    原文链接

    感谢作者ruwatana, 我只是翻译并学习该文. 如果有错误欢迎指正.

    前言

    如果想控制自定义的UIGestureRecognizer的识别,或者同时控制其他手势的失败的情况,我想应该会很多.
    这个时候用UIGestureRecognizerDelegate会方便很多.
    虽然提供了各种各样的方法,但是日语的资料不是很多(原文是日语,本文只是翻译一下),总结了一下哪种情况下会用到哪种方法.

    UIGestureRecognizerDelegate

    UIGestureRecognizerDelegate是一个为了微调手势的识别的protocal.
    它提供了6个协议方法,都是optional的.

    public protocol UIGestureRecognizerDelegate : NSObjectProtocol {
        // 控制Gesture的开始
        @available(iOS 3.2, *)
        optional public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
    
        // 控制Gesture是否可以同时识别
        @available(iOS 3.2, *)
        optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
    
        // 控制自身的Gesture和其他Gesture的失败
        @available(iOS 7.0, *)
        optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
        @available(iOS 7.0, *)
        optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool
    
        // 控制Gesture是否接受touch
        @available(iOS 3.2, *)
        optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
    
        // 控制Gesture是否接受press
        @available(iOS 9.0, *)
        optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool
    }
    

    使用方法

    使用方法很简单.想要实现协议的对象设置为UIGestureRecognizer的delegate就可以了.

    class ViewController: UIViewController {
        var gesture: UIGestureRecognizer?
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // gesture的初始化
    
            // 设置delegate
            gesture?.delegate = self
        }
    }
    
    extension ViewController: UIGestureRecognizerDelegate {
        // 在这里实现delegate方法
    }
    

    delegate方法介绍

    在这里将UIGestureRecognizerDelegate分为三类控制方法介绍

    • 识别控制系方法
    • 同时识别控制系方法
    • 失败控制系方法

    识别控制系方法

    • gestureRecognizerShouldBegin 方法

      • 想要控制识别开始与否的时候, 实现该方法. 可能会是UIGestureRecognizerDelegate中所有方法里用途最多的.
      • UIGestureRecognizer的state会根据.possible, .began, .changed, .ended, .cancelled, .failed这种具体的识别状态发生变化.
      • gestureRecognizerShouldBegin这个方法控制上述状态中的.possible 是变成.began 还是.failed
      • 如果不实现该方法 default返回值是true.
      • 比如, 想实现控制特定的gesture的场合, 使用如下:
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer === tap0gesture { // 判断该gesture是否是指定的gesture 从而进行控制
            // hogehoge
            return false  // tap0click不会被调用
        }
        return true  // tap0click会被调用
    }
    
    • shouldReceive touch方法
      • 会先于ShouldBegin之前被调用, 是控制是否接受touch的.如果返回true,则下一步ShouldBegin()方法会被调用.false的场合ShouldBegin()不会被调用
      • 是控制当前view接不接受touch的场合使用的.
        比如:
    Screen Shot 2017-10-26 at 9.57.06 AM.png

    orangeView的tag是10010

    self.view的tag是10012

    代码:

    class ViewController: UIViewController {
        
        @objc func tap0click(tap: UITapGestureRecognizer) {
            print("tap 10010 click")
        }
        
        @objc func tap2click(tap: UITapGestureRecognizer) {
            print("tap 10012 click")
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // 第一个view
            let view0 = CustomView0(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
            self.view.addSubview(view0)
            view0.backgroundColor = UIColor.orange
            view0.tag = 10010
            let tap0 = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap0click(tap:)))
            view0.addGestureRecognizer(tap0)
            tap0.delegate = self
            
            let tap2 = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap2click(tap:)))
            self.view.addGestureRecognizer(tap2)
            self.view.tag = 10012
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    
    extension ViewController : UIGestureRecognizerDelegate {
        
        func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
            print("gesture recognizer should receive touch in view : \(String(describing: gestureRecognizer.view?.tag))")
            print("gesture recognizer touch in view \(String(describing: touch.view?.tag))")
            return false
        }
        
        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            print("gesture recognizer should begin in view : \(String(describing: gestureRecognizer.view?.tag))")
            return true
        }
    }
    

    返回的结果为:

    Screen Shot 2017-10-28 at 10.16.14 PM.png

    如果shouldReceive回调方法返回值为true

    返回的结果为:

    Screen Shot 2017-10-28 at 10.17.06 PM.png
    • shouldReceive press方法和touch类似.
      • 只支持iOS9以上

    同时识别控制系方法

    • shouldRecognizeSimultaneouslyWith方法
      • 这个方法是同时识别复数个gesture的时候被使用.
      • 比如viewController的view上有一个scrollView的这种情况, 按理来说,会识别最上面那一层的view, 所以scrollView里内置的gesture会被识别, 而被加到viewController.view的自定义gesture不会被识别.
      • 在上面一种情况下,如果利用shouldRecognizeSimultaneouslyWith这个回调方法, 如果设置同时识别两种gesture, 加载viewController.view上的自定义的gesture也会被识别.
      • 使用方法很简单, 想同时识别的两种gesture, 则返回true, 反之返回false.
      • defalult返回值为false
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer === self.gesture { // 判断特定手势
            // hogehoge
        }
    
        if otherGestureRecognizer is UIPanGestureRecognizer { // 判断其他另一个手势
            // hogehoge
        }
    
        if otherGestureRecognizer.view is UIScrollView { // 判断其他手势是加在UIScrollView上的情况
            // hogehoge
        }
        return false
    }
    

    还是上面的orageView那个例子.如果设置同时识别回调方法的返回值为false:

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
    

    返回结果:

    Screen Shot 2017-10-28 at 8.54.07 PM.png

    如果设置返回值为true:

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
    

    返回结果:

    Screen Shot 2017-10-28 at 8.54.39 PM.png

    失败控制系方法

    这个方法是两个gesture都识别的情况下, 控制gestureRecognizer的失败, 或者另一个otherGestureRecognizer的失败的时候使用.

    • shouldRequireFailureOf方法:

      • 这个方法是控制当前gesture本身(设置delegate的gesture)的失败的方法. 此处很容易与另一个失败回调shouldBeRequiredToFailBy混淆, 需要注意.
      • 返回true的时候, 控制当前gesture失败.
      • 在没有其他gesture的情况下,即使返回true也不会失败.
      • default值是false
    • shouldBeRequiredToFailBy方法:

      • 与上面的方法对应, 此方法是控制其他方法的成功与失败.
      • 请注意:如果当前gesture失败的情况下, 也就是上面的shouldRequireFailureOf方法返回的是true(原文里写的是false, 感觉写错了), 根本不会走到shouldBeRequiredToFailBy方法, 所以这种情况无论返回true或者false都不会生效.

    shouldRequireFailureOf方法 返回TRUE时 参数gestureRecognizer会失败.
    shouldBeRequiredToFailBy方法 返回TRUE时 参数otherGestureRecognizer会失败.

    Tips: UIKit中的系统类里使用的gesture是不能设置delegate的.
    不是自定义的gesture, 而是UIKit中封装好的手势(比如UITableView或者UIScrollView的panGestureRecognizer 等等..)

    如果给UITableView(UIScrollView)设置tableview.panGestureRecognizer.delegate = self;, 会崩溃. 提示信息如下:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'
    

    原文点击此处

    相关文章

      网友评论

        本文标题:UIGestureRecognizerDelegate学习笔记

        本文链接:https://www.haomeiwen.com/subject/njphpxtx.html