UIGestureRecognizerDelegate學(xué)習(xí)筆記

原文鏈接

感謝作者ruwatana, 我只是翻譯并學(xué)習(xí)該文. 如果有錯(cuò)誤歡迎指正.

前言

如果想控制自定義的UIGestureRecognizer的識(shí)別,或者同時(shí)控制其他手勢(shì)的失敗的情況,我想應(yīng)該會(huì)很多.
這個(gè)時(shí)候用UIGestureRecognizerDelegate會(huì)方便很多.
雖然提供了各種各樣的方法,但是日語(yǔ)的資料不是很多(原文是日語(yǔ),本文只是翻譯一下),總結(jié)了一下哪種情況下會(huì)用到哪種方法.

UIGestureRecognizerDelegate

UIGestureRecognizerDelegate是一個(gè)為了微調(diào)手勢(shì)的識(shí)別的protocal.
它提供了6個(gè)協(xié)議方法,都是optional的.

public protocol UIGestureRecognizerDelegate : NSObjectProtocol {
    // 控制Gesture的開(kāi)始
    @available(iOS 3.2, *)
    optional public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool

    // 控制Gesture是否可以同時(shí)識(shí)別
    @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
}

使用方法

使用方法很簡(jiǎn)單.想要實(shí)現(xiàn)協(xié)議的對(duì)象設(shè)置為UIGestureRecognizer的delegate就可以了.

class ViewController: UIViewController {
    var gesture: UIGestureRecognizer?
    override func viewDidLoad() {
        super.viewDidLoad()

        // gesture的初始化

        // 設(shè)置delegate
        gesture?.delegate = self
    }
}

extension ViewController: UIGestureRecognizerDelegate {
    // 在這里實(shí)現(xiàn)delegate方法
}

delegate方法介紹

在這里將UIGestureRecognizerDelegate分為三類(lèi)控制方法介紹

  • 識(shí)別控制系方法
  • 同時(shí)識(shí)別控制系方法
  • 失敗控制系方法

識(shí)別控制系方法

  • gestureRecognizerShouldBegin 方法

    • 想要控制識(shí)別開(kāi)始與否的時(shí)候, 實(shí)現(xiàn)該方法. 可能會(huì)是UIGestureRecognizerDelegate中所有方法里用途最多的.
    • UIGestureRecognizer的state會(huì)根據(jù).possible, .began, .changed, .ended, .cancelled, .failed這種具體的識(shí)別狀態(tài)發(fā)生變化.
    • gestureRecognizerShouldBegin這個(gè)方法控制上述狀態(tài)中的.possible 是變成.began 還是.failed
    • 如果不實(shí)現(xiàn)該方法 default返回值是true.
    • 比如, 想實(shí)現(xiàn)控制特定的gesture的場(chǎng)合, 使用如下:
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer === tap0gesture { // 判斷該gesture是否是指定的gesture 從而進(jìn)行控制
        // hogehoge
        return false  // tap0click不會(huì)被調(diào)用
    }
    return true  // tap0click會(huì)被調(diào)用
}
  • shouldReceive touch方法
    • 會(huì)先于ShouldBegin之前被調(diào)用, 是控制是否接受touch的.如果返回true,則下一步ShouldBegin()方法會(huì)被調(diào)用.false的場(chǎng)合ShouldBegin()不會(huì)被調(diào)用
    • 是控制當(dāng)前view接不接受touch的場(chǎng)合使用的.
      比如:
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()
        
        // 第一個(gè)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
    }
}

返回的結(jié)果為:

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

如果shouldReceive回調(diào)方法返回值為true

返回的結(jié)果為:

Screen Shot 2017-10-28 at 10.17.06 PM.png
  • shouldReceive press方法和touch類(lèi)似.
    • 只支持iOS9以上

同時(shí)識(shí)別控制系方法

  • shouldRecognizeSimultaneouslyWith方法
    • 這個(gè)方法是同時(shí)識(shí)別復(fù)數(shù)個(gè)gesture的時(shí)候被使用.
    • 比如viewController的view上有一個(gè)scrollView的這種情況, 按理來(lái)說(shuō),會(huì)識(shí)別最上面那一層的view, 所以scrollView里內(nèi)置的gesture會(huì)被識(shí)別, 而被加到viewController.view的自定義gesture不會(huì)被識(shí)別.
    • 在上面一種情況下,如果利用shouldRecognizeSimultaneouslyWith這個(gè)回調(diào)方法, 如果設(shè)置同時(shí)識(shí)別兩種gesture, 加載viewController.view上的自定義的gesture也會(huì)被識(shí)別.
    • 使用方法很簡(jiǎn)單, 想同時(shí)識(shí)別的兩種gesture, 則返回true, 反之返回false.
    • defalult返回值為false
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer === self.gesture { // 判斷特定手勢(shì)
        // hogehoge
    }

    if otherGestureRecognizer is UIPanGestureRecognizer { // 判斷其他另一個(gè)手勢(shì)
        // hogehoge
    }

    if otherGestureRecognizer.view is UIScrollView { // 判斷其他手勢(shì)是加在UIScrollView上的情況
        // hogehoge
    }
    return false
}

還是上面的orageView那個(gè)例子.如果設(shè)置同時(shí)識(shí)別回調(diào)方法的返回值為false:

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

返回結(jié)果:

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

如果設(shè)置返回值為true:

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

返回結(jié)果:

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

失敗控制系方法

這個(gè)方法是兩個(gè)gesture都識(shí)別的情況下, 控制gestureRecognizer的失敗, 或者另一個(gè)otherGestureRecognizer的失敗的時(shí)候使用.

  • shouldRequireFailureOf方法:

    • 這個(gè)方法是控制當(dāng)前gesture本身(設(shè)置delegate的gesture)的失敗的方法. 此處很容易與另一個(gè)失敗回調(diào)shouldBeRequiredToFailBy混淆, 需要注意.
    • 返回true的時(shí)候, 控制當(dāng)前gesture失敗.
    • 在沒(méi)有其他gesture的情況下,即使返回true也不會(huì)失敗.
    • default值是false
  • shouldBeRequiredToFailBy方法:

    • 與上面的方法對(duì)應(yīng), 此方法是控制其他方法的成功與失敗.
    • 請(qǐng)注意:如果當(dāng)前gesture失敗的情況下, 也就是上面的shouldRequireFailureOf方法返回的是true(原文里寫(xiě)的是false, 感覺(jué)寫(xiě)錯(cuò)了), 根本不會(huì)走到shouldBeRequiredToFailBy方法, 所以這種情況無(wú)論返回true或者false都不會(huì)生效.

shouldRequireFailureOf方法 返回TRUE時(shí) 參數(shù)gestureRecognizer會(huì)失敗.
shouldBeRequiredToFailBy方法 返回TRUE時(shí) 參數(shù)otherGestureRecognizer會(huì)失敗.

Tips: UIKit中的系統(tǒng)類(lèi)里使用的gesture是不能設(shè)置delegate的.
不是自定義的gesture, 而是UIKit中封裝好的手勢(shì)(比如UITableView或者UIScrollView的panGestureRecognizer 等等..)

如果給UITableView(UIScrollView)設(shè)置tableview.panGestureRecognizer.delegate = self;, 會(huì)崩潰. 提示信息如下:

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

原文點(diǎn)擊此處

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容