SwiftUI の VStack・HStack・ZStack で画面を組み立てる

SwiftUI のレイアウトは、3 つのスタックコンテナを組み合わせて構築します。VStack は子ビューを縦方向に、HStack は横方向に、ZStack は奥行き方向に重ねて配置するコンテナです。

VStack:縦に並べる

VStack は子ビューを上から下へ順番に積み重ねます。フォームやリスト風の画面を組むときの基本となるコンテナです。

VStack(alignment: .leading, spacing: 12) {
    Text("タイトル")
        .font(.headline)
    Text("サブタイトル")
        .font(.subheadline)
    Text("本文テキストがここに入ります")
        .font(.body)
}

alignment パラメータで子ビューの水平方向の揃え位置を指定できます。デフォルトは .center ですが、テキスト主体の画面では .leading を指定することが多いでしょう。spacing パラメータを省略すると、システムが各ビュー間に適切な間隔を自動で設定してくれます。

HStack:横に並べる

HStack は子ビューを左から右へ並べます。アイコンとテキストの横並びや、ボタンを横一列に配置するケースで活躍します。

HStack(spacing: 8) {
    Image(systemName: "star.fill")
        .foregroundColor(.yellow)
    Text("お気に入り")
    Spacer()
    Text("12件")
        .foregroundColor(.secondary)
}

HStack の alignment パラメータは垂直方向の揃え位置を制御します。デフォルトは .center で、高さの異なるビューが混在しても中央揃えで統一されます。.firstTextBaseline を指定すると、フォントサイズが異なるテキスト同士をベースラインで揃えることもできます。

ZStack:重ねて配置する

ZStack は子ビューを同じ位置に重ねて描画します。先に書いた子ビューが奥に、後に書いた子ビューが手前に表示される仕組みです。

ZStack(alignment: .bottomTrailing) {
    Image("background")
        .resizable()
        .aspectRatio(contentMode: .fill)
    
    Text("NEW")
        .font(.caption)
        .padding(6)
        .background(Color.red)
        .foregroundColor(.white)
        .cornerRadius(4)
        .padding(8)
}

背景画像の上にバッジを重ねるといった表現に適しています。alignment を .bottomTrailing にすると、手前のビューが右下に寄るため、通知バッジのような配置が簡単に実現できます。

スタックの組み合わせ

実際のアプリでは、3 種類のスタックをネストして複雑なレイアウトを構成します。カード型の UI を例に見てみましょう。

VStack(alignment: .leading, spacing: 8) {
    HStack {
        Image(systemName: "person.circle.fill")
            .font(.title)
        VStack(alignment: .leading) {
            Text("田中太郎")
                .font(.headline)
            Text("3時間前")
                .font(.caption)
                .foregroundColor(.secondary)
        }
        Spacer()
    }
    Text("SwiftUI のスタックを使えば、宣言的にレイアウトを組み立てられます。")
        .font(.body)
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 2)

VStack の中に HStack を入れ、さらにその中に VStack をネストしています。このようにスタックを入れ子にしていくことで、どんなに複雑な画面でも段階的に構築できます。

UIKit のアプローチ

Auto Layout の制約をビュー間に設定し、位置関係を定義していく。制約の数が増えるとコンフリクトの管理が複雑になりやすい

SwiftUI のアプローチ

スタックの入れ子で構造を宣言的に記述する。親子関係が明確で、コードの見た目とレイアウトの構造が一致しやすい

スタックは SwiftUI レイアウトの最も基本的な構成要素です。まずはこの 3 つのコンテナを自在に使いこなせるようになることが、SwiftUI でのアプリ開発の第一歩になります。