SwiftUIにおけるzIndex
は、UI要素の表示順序(重なり順)をコントロールするためのモディファイアだ。
ZStackを利用すれば、複数のビューを重なり合わせることができるが、思うように重なり順をコントロールしにくい時がある。
そのような時にzIndex
が非常に便利だ。
zIndex
を利用すれば、思い通りに複数のビューの重ね合わせ方をコントロールできる。
iOSアプリ開発を始めた時はこのzIndex
の存在を知らずにビューの重なり順の調整でかなり苦労したので、備忘録として残しておく。
zIndexとは?
zIndex
は、ビューのZ軸方向の位置(つまり、前面や背面など)を調整するモディファイアだ。
このモディファイアを使用することで、ビューが他のビューと重なった場合の重なり順を調整することができる。
例えば、zIndex
の値が大きいほど、そのビューは前面に表示される。
デフォルトのzIndex
は0だ。
そのため、zIndex
を指定していないビューはzIndex
=0が自動適用されているとイメージするといいかもしれない。
zIndexの使い方
zIndex
は各ビューに対してzIndex(数字)という形式のモディファイアを指定して表示順を調整する。
具体的なコードとその結果を見ていこう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ZStack { Rectangle() .fill(Color.red) .frame(width: 100, height: 100) .offset(x: -50, y: -50) .zIndex(3) // 最前面に配置 Rectangle() .fill(Color.green) .frame(width: 100, height: 100) .zIndex(2) // 真ん中に配置 Rectangle() .fill(Color.blue) .frame(width: 100, height: 100) .offset(x: 50, y: 50) .zIndex(1) // 最背面に配置 } |
上記コードの結果が下記だ。
zIndex
の値が大きいRectangleビュー(例の場合は赤)が一番上に来ていることがお分かりいただけると思う。
zIndex
を指定しない場合は通常のZStackの挙動になるので、ZStack内で一番下部に指定されたビューが最前面に表示される。
もし真ん中の緑色のRectangleビューを最前面に持っていきたい場合は下記のように最前面に持っていきたいビューのzIndex
に一番大きい値を指定すればOKだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import SwiftUI struct zIndexSample: View { var body: some View { ZStack { Rectangle() .fill(Color.red) .frame(width: 100, height: 100) .offset(x: -50, y: -50) .zIndex(2) // 真ん中に配置 Rectangle() .fill(Color.green) .frame(width: 100, height: 100) .zIndex(3) // 最前面に配置 Rectangle() .fill(Color.blue) .frame(width: 100, height: 100) .offset(x: 50, y: 50) .zIndex(1) // 最背面に配置 } } } |
このようにzIndex
を使用すれば、ビューの重なり順序を思い通りに調整することができる。
zIndexの注意点
zIndex
は表示順を簡単に調整できる便利なモディファイアだが、注意点もある。
同じコンテナ内でのみ有効
zIndex
の値は同じZStack
やHStack
、VStack
といったコンテナ内でのみ有効となる。
例えば、異なるZStack
内のビュー同士では、zIndex
の効果は適用されない。
例えば、先ほどの真ん中のRectangle(緑色)をSubViewとして切り出して、そのサブビューの中で更にZStackで括ってみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import SwiftUI struct zIndexSample: View { var body: some View { ZStack { Rectangle() .fill(Color.red) .frame(width: 100, height: 100) .offset(x: -50, y: -50) .zIndex(2) SubView() Rectangle() .fill(Color.blue) .frame(width: 100, height: 100) .offset(x: 50, y: 50) .zIndex(1) } } } struct SubView : View { var body: some View { //新しくZStackを追加 ZStack{ Rectangle() .fill(Color.green) .frame(width: 100, height: 100) .zIndex(3) } } } |
その結果は下記の通りでSubView内のRectangleにはzIndex
=3が指定されており、一番大きい値になっているが、重なり順は最背面になっている。
理由は他の2つのRectangleビューと別のZStack内に配置されているからだ。
異なるZStack内のzIndex
の値は比較されない。
このようにzIndex
は同じコンテナ(ZStack等)内でのみ比較される点は注意しておきたい。
アニメーションとの併用に注意
zIndex
はアニメーションと組み合わせた際に思わぬ挙動をすることがある。
特に、アニメーションの中でzIndex
を変更すると、ビューがちらつくことがあるため、アニメーションが必要な場合はopacity
やtransition
を使って切り替える方法を選択した方が良いと思われる。
固定値を設定する
zIndex
は変動があるデータに対して動的に適用されると、不安定になる場合がある。
例えば、ForEach
で動的に生成されたビューにzIndex
を付与する場合などは挙動が安定しない場合があるので、固定値で設定する方法を検討してみるといいかもしれない。