SwiftUI の Grid(iOS 16+)で柔軟なグリッドを組む
iOS 16 で導入された Grid は、LazyVGrid よりも細かいセルレベルの制御が可能なグリッドコンテナです。行と列を明示的に定義し、セルの結合(マージ)やカスタム配置を宣言的に記述できます。
基本構造
Grid は GridRow で各行を定義し、その中に子ビューを列として並べます。
Grid(alignment: .leading, horizontalSpacing: 12, verticalSpacing: 8) {
GridRow {
Text("名前")
.fontWeight(.bold)
Text("年齢")
.fontWeight(.bold)
Text("国")
.fontWeight(.bold)
}
Divider()
GridRow {
Text("Alice")
Text("28")
Text("Japan")
}
GridRow {
Text("Bob")
Text("34")
Text("USA")
}
}
.padding()LazyVGrid と違い、Grid は GridItem の配列を定義する必要がありません。各 GridRow 内のビューの数がそのまま列数になり、すべての行の同じ列が自動的に幅を揃えます。
Grid と LazyVGrid の違い
両者は見た目が似ていますが、設計思想が異なります。
すべてのセルを同時にレイアウトする。セルの結合や列ごとの alignment が可能。少数の構造化データ向き
画面外のビューは遅延生成する。大量データの一覧表示向き。セルの結合はできない
Grid は全セルを一度にレイアウトするため、Lazy ではありません。数百行のデータ表示には向きませんが、フォームや表形式の UI には Grid の方が表現力が高くなります。
gridCellColumns でセルを結合する
gridCellColumns モディファイアを使うと、1 つのセルが複数の列にまたがるようになります。
Grid {
GridRow {
Text("項目")
.fontWeight(.bold)
Text("値")
.fontWeight(.bold)
}
Divider()
GridRow {
Text("CPU")
Text("Apple M2")
}
GridRow {
Text("メモリ")
Text("16GB")
}
GridRow {
Text("補足: このスペックは 2024 年モデルのものです")
.font(.caption)
.foregroundColor(.secondary)
.gridCellColumns(2)
}
}
.padding()最後の行で .gridCellColumns(2) を指定しているため、テキストが 2 列分の幅にまたがって表示されます。注釈やフッターなど、行全体を使いたい場面で便利です。
gridCellAnchor でセル内の配置を制御する
Grid 全体の alignment とは別に、個々のセルの配置を gridCellAnchor で上書きできます。
Grid(alignment: .leading) {
GridRow {
Text("左寄せ")
Text("中央寄せ")
.gridCellAnchor(.center)
Text("右寄せ")
.gridCellAnchor(.trailing)
}
GridRow {
Text("Apple")
Text("100")
.gridCellAnchor(.center)
Text("¥200")
.gridCellAnchor(.trailing)
}
}
.padding()商品名は左寄せ、数量は中央、価格は右寄せといったテーブル表現が宣言的に書けます。
GridRow 外のビューは行全体に広がる
Grid の直下に GridRow を介さずビューを置くと、そのビューは全列にまたがって配置されます。
Grid {
GridRow {
Text("A")
Text("B")
Text("C")
}
Divider()
GridRow {
Text("1")
Text("2")
Text("3")
}
}Divider は GridRow で囲まれていないため、3 列分の幅で水平線が引かれます。セクション区切りを入れたいときに、gridCellColumns を使わなくても自然に表現できる仕組みです。
実践例:設定フォーム
Grid を使えば、ラベルと入力フィールドが整列したフォームを簡潔に構築できます。
Grid(alignment: .trailing, horizontalSpacing: 12, verticalSpacing: 16) {
GridRow {
Text("名前")
TextField("入力してください", text: $name)
.textFieldStyle(.roundedBorder)
.gridCellAnchor(.leading)
}
GridRow {
Text("メール")
TextField("example@mail.com", text: $email)
.textFieldStyle(.roundedBorder)
.gridCellAnchor(.leading)
}
GridRow {
Text("メモ")
TextEditor(text: $memo)
.frame(height: 80)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray.opacity(0.3))
)
.gridCellAnchor(.leading)
}
}
.padding()ラベル列は trailing(右寄せ)、入力列は leading(左寄せ)で配置することで、ラベルとフィールドの境界がきれいに揃います。LazyVGrid では実現しにくいこの種の整列が、Grid なら直感的に書けるのが大きな魅力です。