post Image
よくわかるUIGestureRecognizerDelegate

はじめに

カスタムで作ったUIGestureRecognizerの認識を制御したり、他のジェスチャーとの同時認識や失敗の制御をしたいことは多々あると思います。
その際に、便利なのがUIGestureRecognizerDelegateです。
色々なメソッドが提供されていますが、日本語の資料があまり多くないので、どれがどういった時に役に立つかをまとめてみました。

UIGestureRecognizerDelegate

UIGestureRecognizerDelegateはアプリのジェスチャー認識の振る舞いを微調整するためのprotocolです。
UIKitのUIGestureRecognizerDelegateには以下のメソッドが提供されています。
すべてoptionalです。

UIKitから抜粋
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に受け取りたい先のインスタンス(基本的にVCになると思います)をセットし、UIGestureRecognizerDelegateを実装するだけです。例を示します。

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

        // gestureの初期化処理を行う

        // delegateのセット
        gesture?.delegate = self
    }
}

extension ViewController: UIGestureRecognizerDelegate {
    // ここに必要なdelegateメソッドを実装していく
}

それぞれのdelegateメソッドの詳細

ここからは、それぞれのdelegateメソッドの使い方を以下の3つの制御分類に分けて、例とともに紹介していきます。

  • 認識制御系メソッド
  • 同時認識制御系メソッド
  • 失敗制御系メソッド

認識制御系メソッド

gestureRecognizerShouldBeginメソッド

Gestureの認識を開始させるかの制御を行いたいときは、gestureRecognizerShouldBegin()メソッドを実装します。
UIGestureRecognizerDelegateのメソッドの中でも一番使用用途が多いかもしれません。
UIGestureRecognizerはstateプロパティを持っており、.possible, .began, .changed, .ended, .cancelled, .failedといった具合に認識状況に応じて変化していきます。
このstateでいうところの、.possibleから.beganになるべきか.failedになるべきかをこのメソッドで制御できます。
このメソッドを実装しない場合は、デフォルトでtrueが返ります。
例えば、特定のgestureのみを制御させたいときは、下記のように使えます。

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer === self.gesture { // 特定のgestureを捕捉して認識させるか制御
        // hogehoge
    }
    return true
}

shouldReceive touchメソッド

touchesBegan()より前に呼ばれるメソッドで、touchを受け取るかどうかを制御します。
trueを返すと、その後touchesBegan()メソッドが呼ばれます。falseの場合は呼ばれません。
このviewからのtouchは受け取らないといった制御を入れたい時に使うことができます。

shouldReceive pressメソッド

iOS9から利用可能になったメソッドです。
pressesBegan()より前に呼ばれるメソッドで、pressを受け取るかどうかを制御します。
trueを返すと、その後pressesBegan()メソッドが呼ばれます。falseの場合は呼ばれません。
このviewからのtouchは受け取らないといった制御を入れたい時に使うことができます。

同時認識制御系メソッド

shouldRecognizeSimultaneouslyWithメソッド

このメソッドは、複数のGestureを同時認識させたい時に使います。
例えば、VCが持つviewの上に貼ったUIScrollView系のViewがいる場合を考えます。
認識の優先度的には、最前面のGestureが認識されるので、ScrollViewの中に設定されているGestureの方が優先されてしまい、VCが持つviewにaddしたカスタムGestureはこのままでは、認識できません。
そこで、このメソッドを用いて、同時認識を許可してあげることによって、カスタムのGestureも認識させることができるようになります。

使い方は簡単で、同時認識させたい場合は、trueを返してあげればよいです。
逆に同時認識をさせたくない場合はfalseを返しましょう。このメソッドを実装しない場合はデフォルトでfalseが返ります。
このメソッドでは、競合するGestureをotherGestureRecognizerで取得できるので、そのGestureのクラスや親のViewのクラスによって制御することもできます。
下記に例を示します。

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer === self.gesture { // 特定のgestureのとき
        // hogehoge
    }

    if otherGestureRecognizer is UIPanGestureRecognizer { // 他方がPan(ドラッグ)Gestureのとき
        // hogehoge
    }

    if otherGestureRecognizer.view is UIScrollView { // 他方のGestureの親がUIScrollViewのとき
        // hogehoge
    }
    return false
}

失敗制御系メソッド

これらは、2つのGestureの認識が競合した時に自身が失敗をするか/他方の失敗をさせるか制御するメソッドです。
どっちがどっちだっけ?と混同しやすいので注意が必要です。

shouldRequireFailureOfメソッド

このメソッドは、delegateをセットしたGesture自身が他のGestureによって失敗されるかどうかを制御します。
もう一つの失敗制御メソッドのshouldBeRequiredToFailByと混同しやすいので注意してください。
このメソッドの返り値をtrueにすることで、他のGestureによって自身のGestureが失敗させられることを許可します。
もちろん、他のGestureが失敗を要求しない限りは自身のGestureが失敗させられることはありません。
このメソッドを実装していない場合は、デフォルトではfalseが返るため、他のGestureによって失敗させられることはありません。

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    // trueなら他のGestureによって失敗要求が出された場合、失敗する
    return true
}

shouldBeRequiredToFailByメソッド

上に対して、こちらはGesture自身が他のGestureに対して失敗を要求するかどうかを制御します。
一見、英語からすると意味が逆なのではと思う方もいると思いますが、これで正しいです。
このメソッドの返り値をtrueにすることで、ほかのGestureは失敗が要求されます。
注意が必要なのは、他のGestureがshouldRequireFailureOfメソッドによって、失敗されないように制御されていた(falseを返していた)場合、ここでtrueを返しても他のGestureが失敗されることはありません。
このメソッドを実装していない場合は、デフォルトではfalseが返るため、他のGestureに失敗の要求をすることはありません。

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    // trueなら他のすべての競合するGestureに対して失敗要求を出す
    return true
}

Tips: UIKitのクラスで使われているGestureはdelegateをセットできない

カスタムで作ったGestureRecognizerではなく、UIKitの中で使われているアクセス可能なGestureのdelegateも実装したいと考える方もいると思います。
が、これらのGestureのdelegateをセットした場合、エラーが出てクラッシュしてしまうので注意が必要です。

下記は、UITableView(UIScrollView)のpanGestureRecognizerのdelegateをセットした際に実行した時のエラーログです。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'

まとめ

UIGestureRecognizerDelegateを正しく理解して、ユーザにとって使いやすい、適切なジェスチャーハンドリングを実装しましょう。

参考リンク


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。