UIGestureRecognizerDelegate学习笔记

原文链接

感谢作者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.'

原文点击此处

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,763评论 6 539
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,238评论 3 428
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 177,823评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,604评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,339评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,713评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,712评论 3 445
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,893评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,448评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,201评论 3 357
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,397评论 1 372
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,944评论 5 363
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,631评论 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,033评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,321评论 1 293
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,128评论 3 398
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,347评论 2 377

推荐阅读更多精彩内容