2014年8月12日火曜日

UINavigationController.interactivePopGestureRecognizer の挙動を魔改造して変えてみる

注意: 今回の記事は久しぶりの誰得記事です。こちらで紹介されている手法を用いるにはプライベートAPIを操作する必要があるため、おそらく審査に通りません。じこせきにんでお願いします。

iOS 7からUINavigationControllerにinteractivePopGestureRecognizerというプロパティが新たに追加されました。これは「ナビゲーションコントローラの左端から右にスワイプすると前の画面に戻る」機能を司るgesture recognizerで、同じくiOS 7から追加されたUIScreenEdgePanGestureRecognizer(画面端からのみ反応するPan Gesture Recognizer)とUIViewControllerInteractiveTransitioning(ViewController間の画面遷移時に、ユーザーのインタラクションを追加する。例えば画面半分までスワイプしたら50%画面遷移するとか)の仕組みで実装されています。

ここで、例えばこの「ナビゲーションコントローラの左端から右にスワイプすると前の画面に戻る」機能について、見た目はそのままがいいんだけど左端からしか反応しないのが気に入らないから画面の中央でも反応するようにしたいという要望があったとします。自前で実装してもよいのですが、やはりApple純正の動きが良いですよね。

そこで以下のページで紹介されている黒魔術を使ってみたいと思います。
http://blommegard.se/blog/2014/01/31/a-take-on-custom-transitions-with-uinavigationcontroller/
こちらのページにUINavigationController内部でどのようにinteractivePopGestureRecognizerが実装されているかという解説があります。

  • 先述の通り、UIScreenEdgePanGestureRecognizerのインスタンスが使用されている
  • targetは_UINavigationInteractiveTransition型のオブジェクト、調査の結果_cachedInteractionControllerという隠しプロパティがそれに相当することがわかった
  • actionは@selector(handleNavigationTransition:)

ここまでわかったので、あとはtarget/actionを自分で生成したUIGestureRecognizerにセットしてやれば、標準の動きをジャックすることができるというわけです。今回はUIPanGestureRecognizerを使用しました。



このコードを実行してみると確かに画面中央からでもいつものスワイプジェスチャで戻る挙動が可能になっています。やりましたね\(^o^)/