UINavigationControllerのinteractivePopGestureRecognizerの感度を調整する

  • 55
    Like
  • 0
    Comment
More than 1 year has passed since last update.

普段、左手でiPhoneを操作している人は、iOS7になってから毎日こんな経験をしているのではないでしょうか。

ひどいUXですね

これでは、本来の縦スクロール操作が慎重になってしまい、ストレスが募るばかり。。それもこれも、UINavigationControllerinteractivePopGestureRecognizer(UIScreenEdgePanGestureRecognizerクラス)の感度が高すぎるのが原因です。

そこで改善策として、UIScreenEdgePanGestureRecognizerクラスをメソッド差し替え(swizzle)して感度調整する涙ぐましい方法などがありますが、今回はそれよりももっと簡単で良い方法が見つかったので、その情報共有をします。

ヒントは、Facebookアプリでした。

interactivePopGestureRecognizer.delegateを自前で実装する(ただし、注意点あり)

標準のUINavigationControllerのジェスチャー+トランジションを使って感度調整を行っている(と思われる)アプリは、手元のインストール済みアプリの中では、Facebookだけでした。このアプリでは、

  • コンテンツのスクロール中に、interactivePopGestureRecognizerを実行しない

という上手い処理が入っているようで、似たところでは、Twitter公式アプリもそのような挙動になっていました。つまり、

// viewWillAppearあたり
self.navigationController.interactivePopGestureRecognizer.delegate = self;

...

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) {

        // (1)
        if (self.tableView.dragging) return NO;

        // (2) 
        return [self.navigationController.viewControllers count] > 1;
    }
    return YES;
}

と(1)のように書くのが、よりスマートな方法と言えます。

ただし、注意点として、interactivePopGestureRecognizer.delegateを標準の_UINavigationInteractiveTransitionから勝手に奪っているので、 自己責任のもと、取り扱いにくれぐれも注意する 必要があります。(カスタムleftBarButtonItemをセット→popGestureを再度ONにした場合も同様)

One problem with this method is if you perform an edge pan on a root view it will lock up the UI

(意訳)navigationControllerのrootViewController内でinteractivePopGestureRecognizerを実行すると、UIがおかしくなるよ

この対策として、(2)も合わせて入れておくと良いでしょう。

まとめ

左利きにも優しいUIができた Appleが最初から頑張ればこんなことにはならなかった

上記サンプル