はじめに
Viewの遷移時にアニメーションするにて画面遷移の実践をしてみました。
この方法について、見た目上しっくりと来ない部分があったので、対応策を残しておきたいと思います。
現象
状況の説明
アプリ起動時に画面Aを表示し、画面Aでの処理に応じて画面Bに切り替えるケースで考えていきます。切替時には画面Aをアニメーションで閉じています。
起動してからのアプリの流れは、
- 画面Aの描画
- 画面Bへの遷移可否判定
- 画面Bの描画と画面Aのアニメーションによる消去
このとき期待していた動きは、画面Aの裏側に画面Bを表示しておいて、画面Aをアニメーションで消すに従って画面Bが現れるというものです。ですが、実際は画面Bは画面Aの前面に表示されてしまい、画面Aがそもそも見えない状況になりました。これではアニメーションの意味がありません。
画面Bの背景色が透明で内包するViewもあまりない状態ならばこれでも構いません。ですが、そのようなパターンはあまりないように思います。
コード例
コードを必要最低限で抜き出してみました。画面AとBを呼び出している概念的なコード例はこのような感じになります。
var body: some View {
ZStack {
if 画面Aでの処理後、画面Bへの遷移OK {
画面B
}
else {
画面A
}
}
}
画面Aのコード例は、
var body: some View {
return GeometryReader { geometory in
VStack (alignment: .leading, spacing: 12.0) {
諸々のView(ここで画面Bへの遷移可能かどうかを判定して戻している)
}
.padding(8.0)
.frame(width: geometory.size.width, height: geometory.size.height)
.background(Color.white)
.animation(.easeInOut(duration: 0.4))
}
.transition(.move(edge: .bottom))
}
画面Bのコード例は、
var body: some View {
return VStack (alignment: .leading, spacing: 12.0) {
諸々のView
}
.padding(8.0)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.orange)
}
対応方法
試行錯誤の結果、解決策を見つけました。描画される順序を確定させておく方法です。
var body: some View {
ZStack {
if 画面Aでの処理後、画面Bへの遷移OK {
画面B
}
else {
画面A
.zindex(9) //インデックスの値は1以上の任意の値
}
}
}
画面Bへの遷移OKとなった時点で、画面Bの描画がなされます。なされると同時に画面Aを閉じるアニメーションも実行されます。このときの順序は画面Aが画面Bの下に存在する状態です。ならば、ハナから「画面Aは画面Bよりも前面ですよ」と指定しておけばよいのです。
上記コード中のzindex(9)
がミソです。何も指定しないときは0が設定されています。1より大きい値を指定した順でViewが前面から表示されます。
まとめ
以上、フラグによる画面遷移をする場合の、Viewの重なり順序による見た目の改善方法でした。(アニメーションの時間をぐっと短くすれば気にはならないんですがね)
ちなみに、画面Bから画面Aへの遷移もできますが、上記のコードだと画面Bが消え去って画面Aのアニメーションが開始されます。これはこれで頂けないので、画面Bを表示(かつ操作不可)した状態で画面Aをアニメーション表示する方法も検討しないといけません。