スワイプで戻る操作のキャンセルを検知したい
ざっくりまとめ。
- スワイプで戻る操作を途中でキャンセルした場合を検知したい...どうしたら🤔
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
これの通りです🙏
だいぶ昔だから...今はもっとベストなのがあるかも...?