iOS13からモーダルを表示するときはセミモーダルがデフォルトの挙動となりました。
完全なフルスクリーンではなく後ろのViewが少し見えるようなデザインで、下にスワイプで元のViewに戻ることができます。
これをされると困るデザインがあります。例えばログイン後に表示されるViewはセミモーダルではなくフルスクリーンで表示したいでしょう。
StoryboardからPresentationをFullscreen
にすることで次のモーダルを完全なフルスクリーン状態で遷移できます。
Swiftの場合はこうします。
let vc = ViewController()
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true)
この状態であればスワイプで戻ることもできません。
ここまでであればあまり問題はなさそうに見えます。
さらにModalで遷移したいとき
ここからさらにモーダルを表示したいとします。このときはセミモーダルのほうが利便性があがるので普通の遷移にします。
するとどうでしょう。
なんと後ろのViewが下がらないままセミモーダルが出てしまいました。
iOS13においてfullscrrenでモーダル表示したものはずっとfullscreenの状態を維持するのでこのような動きになるようです。
でもこれじゃかっこよくない!下がってほしい!というときはCurrent Context
を使ってみます。
先ほどのFullscrrenからCurrent Contextに変更します。するとStoryboard上では灰色はフルスクリーンで、その次のモーダルでは灰色Viewが下にずれているのが確認できます。
(よく見ると上のStoryboardでもFullscreen選択時のモーダルの見え方はシミュレートされていましたね)
ではこれで解決!かと思いきや実際実行してみると・・・
なんと今度はステータスバーが全く見えなくなってしまいました。
CurrentContext時にStatusBarを見えるようにする
これは推測ですが、CurrentContextによって諸々の状態を参照する先が灰色のViewになっているのだと思われます。灰色Viewの時点ではステータスバーは黒色テキストなので、モーダル遷移後も灰色Viewからステータスバーの情報を取得していると考えると、黒の背景に黒のテキストとなってしまい見えなくなってしまったものと考えられます。
これを回避するにはViewController毎にステータスバーの色は何色にすべきかという情報を設定します。
灰色のViewControllerにpreferredStatusBarStyle
プロパティをオーバーライドします。
class ViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
if presentedViewController != nil {
return .lightContent
} else {
return super.preferredStatusBarStyle
}
}
}
presentedViewController
は現在のViewController(灰色)からみてさらにモーダル表示しているViewControllerがあればそのViewControllerが、なければnilが返ってきます。
つまりpresentedViewControllerがnilでないなら何かしらモーダルを表示しているということです。
このときはステータスバーを白とし、それ以外はデフォルトの挙動としました。
ここを拡張することでもう少し細かな要望にも応えることができます。例えば次のModalもフルスクリーンだったらデフォルト挙動にするとかですね。
青色のViewControllerのpreferredStatusBarStyleは参照されませんでした。これもCurrentContextが影響していると考えられます。