美文网首页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