SwiftUI モディファイアの適用順序
SwiftUI のモディファイアは、適用する順序によって結果が大きく変わる。これは SwiftUI の根本的な仕組みに関わる重要な概念で、理解しないと意図しないレイアウトに悩まされることになる。
モディファイアは「ラップ」する
SwiftUI のモディファイアは、元のビューを新しいビューで包み込む。チェーンの各ステップで新しいビューが生成される。
Text("Hello")
.padding()
.background(.blue)このコードは、Text を Padding でラップし、さらにそれを Background でラップしている。結果として、青い背景はパディングを含む領域に適用される。
Text("Hello")
.background(.blue)
.padding()順序を入れ替えると、青い背景は Text のみに適用され、パディングは背景の外側に追加される。
視覚的な違いを確認
// パターン A: padding → background
Text("A")
.padding(20)
.background(.red)
// パターン B: background → padding
Text("B")
.background(.red)
.padding(20)テキストの周りにパディングがあり、その全体が赤い背景で覆われる。背景は大きい。
テキストだけが赤い背景で覆われ、その外側にパディングがある。背景は小さい。
frame の順序
frame も同様に順序が重要だ。
Text("Hello")
.frame(width: 200, height: 100)
.background(.green)
.frame(width: 300, height: 150)
.background(.orange)最初の frame で 200×100 の領域が確保され、緑の背景がそこに適用される。次の frame で 300×150 に拡大され、オレンジの背景は拡大後の領域に適用される。緑の矩形がオレンジの矩形の中央に配置された、入れ子構造になる。
クリッピングと角丸
cornerRadius(または clipShape)と frame の順序も影響を受ける。
// 角丸が内側に
Image("photo")
.resizable()
.frame(width: 100, height: 100)
.clipShape(RoundedRectangle(cornerRadius: 20))
// 角丸が外側に
Image("photo")
.resizable()
.clipShape(RoundedRectangle(cornerRadius: 20))
.frame(width: 100, height: 100)最初の例では、100×100 にリサイズしてから角丸でクリップする。2 番目は先にクリップしてからリサイズするため、角丸の比率が変わる可能性がある。
影の順序
shadow も順序の影響を受ける典型例だ。
Text("Shadow")
.padding()
.background(.white)
.shadow(radius: 5) // 背景全体に影
Text("Shadow")
.padding()
.shadow(radius: 5) // テキストだけに影
.background(.white)shadow はそれより上のモディファイアで構成されたビュー全体に適用される。background を shadow の後に置くと、背景には影がつかない。
複数の同じモディファイア
同じモディファイアを複数回使うこともできる。
Text("Nested")
.padding(10)
.background(.red)
.padding(10)
.background(.blue)
.padding(10)
.background(.green)赤→青→緑と入れ子になった背景が作られる。これを利用して、ボーダー風の効果を作ることもできる。
overlay と background
overlay と background も順序に注意が必要だ。
Rectangle()
.fill(.blue)
.frame(width: 100, height: 100)
.overlay(
Circle().fill(.red).frame(width: 50, height: 50)
)
.padding()overlay は「その時点でのビュー」の上に重ねる。padding を overlay の後に置くと、赤い円は青い四角形の中央に配置されたまま、全体にパディングが追加される。
実用的なガイドライン
frame、padding などは、コンテンツに近い位置から適用していくのが基本。
background、border、shadow は、装飾したいビューの直後に置く。
clipShape は、最終的なサイズが決まった後に適用するのが一般的。
モディファイアの順序を意識することで、予測可能なレイアウトが実現できる。迷ったときは、各ステップで background(.red.opacity(0.3)) などを挟んでデバッグすると、どの段階でどのサイズになっているかが可視化できる。












