先に結論
-
modalPresentationStyle = .pageSheetかつisModalInPresentation = falseの場合はスクラブジェスチャでモーダルをdismiss - それ以外(多分)はpopして、popするものがなくなったら
accessibilityPerformEscape()を見に行く。
accessibilityPerformEscape
そもそもaccessibilityPerformEscape()とは...
VoiceOverがオンのときに、二本指のスクラブジェスチャ(二本指でZを描くようなジェスチャ)によって、モーダル(もしくは階層)を閉じるためのメソッドであり、アクセシビリティ要素が特定の動作をサポートするためのメソッド群UIAccessibilityAction一つらしいです。
accessibilityPerformEscape()の中にスクラブジェスチャによって発火させたい処理(閉じる系以外の処理以外は書かない方が無難ですね)を書くと、スクラブジェスチャによって画面を閉じたり戻したりできます。
試しにVoiceOverを起動して適当なアプリ(SettingsとかSafariとか)を開いてスクラブジェスチャしてみると、popしたりdismissしたりします。
ドキュメント↓
UINavigationControllerにおけるスクラブジェスチャのデフォルト挙動
ところで、ドキュメントによるとaccessibilityPerformEscape()のデフォルト実装は戻り値としてfalseを返すようです。
この戻り値は、モーダルが正常に閉じられたかどうかなので、falseを返すということは中身は空ということじゃないのかなと思います。
なんですけど、UINavigationControllerは何も実装していなくても普通にスクラブジェスチャ効くんですよね、よくわからん。誰か詳しい人教えてください。
というわけで、accessibilityPerformEscape()をoverrideする上でUINavigationControllerのデフォルトの挙動に準じた動作をさせられるように、挙動を知っておくことは有意義だと思って色々触ってみたわけです。
試しに以下のような階層のアプリを作りました。
VC1, VC2, NavではそれぞれaccessibilityPerformEscape()をoverrideしてdismissするようにしています。
- VC1
- Nav
- VC2
- VC3
- Nav
ここで、VC3を開いた状態からスクラブジェスチャを複数回行うことでNavのmodalPresentaitonStyleとmodalInPresentationを変更してそれぞれどんな挙動をするか、どのaccessibilityPerformEscapeが呼ばれるのかを確認してみました。
以下の表が結果です
| modalPresentationStyle | modalInPresentaion | 挙動 | 呼ばれたaccessibilityPerformEscape() |
|---|---|---|---|
| .pageSheet | true | VC3 -> VC2 -> VC1 | VC2 -> VC1 のタイミングで VC2のメソッドが呼ばれる |
| .pageSheet | false | VC3 -> VC1に遷移 | - |
| .fullscreen .formSheet .popOver |
true / false | VC3 -> VC2 -> VC1 | VC2 -> VC1 のタイミングで VC2のメソッドが呼ばれる |
他にもmodalPresentationStyleは定義されていますが、.pageSheet以外変化ないので面倒になって確認していません。(誰か...)
多分同じということにしておきましょう!!