SwiftUI モディファイアはつける順番が大事!

Swiftでもたまにプロパティを設定する順番によって期待する動作と違うこともありましたが、SwiftUIではそれがより明確に表れる印象です。
今学習2日目で分かりやすいケースに出会ったのでちょっとしたメモとして記事にします。

モディファイアの順番によって何が違うの?

完成レイアウト

struct HomeView: View {
    var body: some View {
        VStack(alignment: .leading) {
            IconView(iconImage: nil)
            TitleView(title: "")
            SubTitleView(language: "", star: 0)
            DescriptionView(description: "")
        }
        .padding(24)
        .overlay {
            RoundedRectangle(cornerRadius: 20)
                .stroke(Color.gray, lineWidth: 1)
        }
        .padding(16)
    }
}

なんでpadding を2箇所で付けてるの?という疑問を初学者なら誰しも感じたことがあるのではないでしょうか?

感覚的にはSwiftで以下のようなことをしている感じ。

let view = UIView()
let childView = UIView()
view.frame.origin.x = 24
view.addSubview(childView)
view.frame.origin.x = 16

ちょっと違うかな?🤔
まぁとりあえず後から設定したpaddingで上書きされるんじゃないか?と直感的には読み取ってました。

ということでモディファイアを1つずつ付けていきレイアウトへの反映のされ方を確認していきましょう。

下記の左から
1. モディファイアなし
2. padding(24)のみ設定
3. 上記に追加して overlay設定
4. 上記に追加して padding(16)設定
を設定した時のレイアウトになります。

この結果に違和感はないのですが細かく見ていきます。

  1. VStackに対してpadding(24)を設定しているのでVStackとその子要素の間にスペースができます。
    (この勘違いは自分だけかもしれないですがpaddingはVStack自体のサイズが変わっている訳ではないです)
  2. overlayの設定をする。
    ・overlayに設定している RoundedRectangleはサイズを設定していない場合、親要素いっぱいに広がる特性を持っています。(たぶん)
    ・padding(24)の後に設定しているためこのpadding(24)というモディファイアの影響は受けません。
  3. 最後にpadding(16)の設定をしています。
    これはoverlayの後に設定しているためoverlayの要素にも影響があります。
    そして、paddingモディファイアは複数つけた場合でも上書きではなく追加されるみたいなので、
    VStackのpaddingは合計で40になり、overlayのpaddingは16になります。

まとめ

知ってしまえばあ〜そうなんだ〜くらいのことですが最初微妙に違和感を感じることではないでしょうか?
最初違和感を持つもののそのあとは感覚的にできるようになっていくものかと思うので、どのように反映しているのかを今のうちに言語化してまとめてみました。

2024年12月28日 名古屋のバンテリンドームで行われるNissyのライブでお会いしましょう!
ではまた〜!