anz blog

スワイプで戻る操作のキャンセルを検知したい

2018-07-18 #Swift

ざっくりまとめ。

  • スワイプで戻る操作を途中でキャンセルした場合を検知したい...どうしたら🤔
  • notifyWhenInteractionChanges(_:)で検知できる!
  • なぜそのような物が必要になったのかっていう雑談

です。

環境

  • Xcode v9.4.1
  • Swift v4.1

何がしたいのか

スワイプで戻る操作を途中でキャンセルしたことを検知したい。。。!

UINavigationControllerを使って push で画面遷移をしていったとき、
ナビゲーションバーの戻るボタンでももちろんまえの画面にもどれますが、
スクリーンの左端からスワイプすることでも戻れます。
(スワイプ操作にあわせてスクリーンが移動する感じで)
この操作をすると...

  • スワイプをきっちりやって、前の画面にもどる!
  • 途中でやめて、今の画面に居続ける...

という2つのパターンがありますが、これ...どっちが発生したいのか知りたいっていうことです。

方法

先に結論から。

notifyWhenInteractionChanges(_:)というものが用意されているので、これをつかって検知することができます!💪

すぐには利用できなくって、UINavigationControllerDelegateを利用しつつやっていきます。(他にもあるとおもいますが...)

以下コード

class NavigationController: UINavigationController {

    public override func viewDidLoad() {
        super.viewDidLoad()
        
        delegate = self
    }
}

extension NavigationController: UINavigationControllerDelegate {

    public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    
        viewController.transitionCoordinator?.notifyWhenInteractionChanges { context in
            
            if context.isCancelled {
                // キャンセルされた!(今の画面に居続けた)
            } else {
                // 完了した!(前の画面にもどった!)
            }
        }
    }
}

これで検知できます!

BaseViewController みたいのがあって全画面でそれを継承してる場合なんかは、
UINaivgationControllerDelegateとかつかわなくても、その Base でやっちゃえそうですかね。。

なぜこれが必要になったのか...🤔

UINavigationControllerのサブクラスを作って、popViewController(animated:)を override して、
それをトリガーにゴニョゴニョしていたのですが...

このスワイプで戻る操作をした場合、操作中でまだ戻るのか留まるのか決まっていない状態のときに、すでにpopViewController(animated:)が呼ばれてしまうわけです。
で、そのまま前の画面に戻った場合はまだいいとしても、途中でやめてキャンセルした場合...「え?どうするの??」みたいな感じになりまして...。
「ここが通る≒画面戻った(完了した)」と思っていたので...

キャンセルした場合に
pushViewController(_:, animated:)とかsetViewControllers(_:, animated:)とかが改めて呼ばれるわけでもなく...
どうにかpopViewController(animated:)がなかったことにしたいのだけれど...

ってなって、この話題が出てきたというわけです。
なんか...UINavigationControllerDelegateにちゃんと組み込まれる形でほしいですけどね。。。😭

参考

ios - Getting interactivePopGestureRecognizer dismiss callback/event - Stack Overflow
これの通りです🙏
だいぶ昔だから...今はもっとベストなのがあるかも...?