【Swift UI】グリッドレイアウトの実装方法!LazyVGridとGridItemの使い方
この記事からわかること
- SwiftUIでグリッドレイアウトを実装する方法
- LazyVGridやGridItemの使い方
- グリッドレイアウト個数や余白の調整
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- macOS:Sonoma 14.6.1
SwiftUIを使ってグリッドレイアウトを簡単に実装できるLazyVGridとGridItemの使い方をまとめていきます。
SwiftUIで実装できるグリッドレイアウト
グリッドレイアウトとはWebサイトなどのデザインの1つで格子状に分割され、ブロックを並べたようにコンテンツを配置する手法のことです。
SwiftUIでは以下のようなグリッドレイアウトを簡単に実装することができます。
実装するにはLazyVGrid(LazyHGrid)
とGridItem
の使い方を覚える必要があります。
LazyVGrid(LazyHGrid)の使い方
LazyVGrid(LazyHGrid)
とは中にある要素をグリッドレイアウトに自動で並べてくれる構造体です。Vはvertical(縦方向)にHはHorizon(横方向)に並べる構造体です。LazyVGrid(LazyHGrid)に渡すコンテンツクロージャの中には並べたい要素を記述し、最初に記述した要素から順番に並んでいきます。
LazyVGrid
LazyVGrid(columns: columns){
要素1
要素2
要素3
}
LazyHGrid
LazyHGrid(rows: rows) {
要素1
要素2
要素3
}
引数はGridItem型で設定
引数にはグリッドレイアウトのサイズや余白、並べる個数などをGridItem型
で指定した配列を渡します。配列なのでGridItem型の要素数は任意の数指定可能です。
let columns = [GridItem(.flexible())]
中に記述した要素数の数分だけLazyVGridでは列(LazyHGridでは行)が増えていきます。ここは後で詳しく見ていきます。
let columns = [GridItem(.flexible()),GridItem(.flexible())]
GridItemの引数
init(GridItem.Size, spacing: CGFloat?, alignment: Alignment?)
GridItemの引数は上記の通りになっています。Size
にはfixed
などいずれかの指定値とサイズ数を指定します。spacing
には余白を、alignment
はどこに揃えるかを指定できます。
Sizeに指定できる値
// 画面サイズに合わせたサイズになる
adaptive(minimum: CGFloat,maximum: CGFloat = .infinity)
// 指定した固定サイズ
fixed(CGFloat)
// 指定した範囲内のサイズ
flexible(minimum: CGFloat = 10,maximum: CGFloat = .infinity)
グリッドレイアウトを実装する
例えば要素を縦に2列で並べるならLazyVGridを使って下記のように記述します。
// 2列分のGridItem要素を用意する
let columns = [GridItem(.fixed(80)),GridItem(.fixed(80))]
var body: some View {
ScrollView() {
LazyVGrid(columns: columns) {
ForEach((1...50), id: \.self) { num in
Text("\(num)")
.padding()
.cornerRadius(8)
.frame(width:80,height: 80)
.background(Color.green)
}
}
}
}
同様に横に4行で並べる場合はLazyHGridを使って下記のように記述します。
// 4行分のGridItem要素を用意する
let rows = [GridItem(.fixed(80)),GridItem(.fixed(80)),GridItem(.fixed(80)),GridItem(.fixed(80))]
var body: some View {
ScrollView() {
LazyHGrid(rows: rows) {
ForEach((1...50), id: \.self) { num in
Text("\(num)")
.padding()
.cornerRadius(8)
.frame(width:80,height: 80)
.background(Color.orange)
}
}
}
}
GridItem要素を格納した配列の要素数を変化させることで列数(行数)の調整が可能になります。
グリッドレイアウトを実装するポイント
- LazyVGridは中の要素を縦に並べる
- LazyHGridは中の要素を横に並べる
- 引数にはGridItem要素を持った配列を渡す
- 配列の要素数によって列(行)数を調整
GridItem要素を持った配列を簡素化する
GridItem要素を持った配列は同じ値を指定することが多いです。その場合以下のように記述しても問題はないですが、可読性が低く、冗長的です。
let rows = [GridItem(.fixed(80)),GridItem(.fixed(80)),GridItem(.fixed(80)),GridItem(.fixed(80))]
これを解決する方法としてArray
のイニシャライザを活用します。活用した場合は以下のようになります。
let grids = Array(repeating: GridItem(.fixed(80)), count: 4)
Arrayのイニシャライザ
init(repeating repeatedValue: Element,count: Int)
上記のArrayのイニシャライザは指定された要素を指定された回数分含んだ配列を返します。引数repeating
には繰り返したい要素を、引数count
には回数を指定します。
let ThreeAme = Array(repeating: "ame", count: 3)
print(ThreeAme) // ["ame", "ame", "ame"]
簡素化したコード
今回はrepeating
の後にGridItem型の要素をcount
にはグリッドレイアウトで並べたい列数(行数)を指定します。
let grids = Array(repeating: GridItem(.fixed(80)), count: 2)
var body: some View {
ScrollView() {
LazyVGrid(columns: grids) {
ForEach((1...50), id: \.self) { num in
Text("\(num)")
.padding()
.cornerRadius(8)
.frame(width:80,height: 80)
.background(Color.green)
}
}
}
}
カスタムグリッドレイアウト
通常のグリッドレイアウトではなく行と列を跨ぐようなアイテムの絡んだグリッドレイアウトを実装したくなりました。しかしこれがなかなか思うように実装できず、LazyVGrid
やGrid
などを使用した方法では期待通りにできませんでした。
結論HStack
やVStack
を使用して力技での実装になりましたので一応コードを添付しておきます。良い方法があったらお問い合わせより教えてください。
struct GridView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0..<10) { _ in
HStack {
ForEach(0..<3) { _ in Square() }
}
HStack {
Square(width: (UIScreen.main.bounds.width / 3 - 16) * 2)
VStack {
Square()
Square()
}
}
HStack {
ForEach(0..<3) { _ in Square() }
}
HStack {
VStack {
Square()
Square()
}
Square(width: (UIScreen.main.bounds.width / 3 - 16) * 2)
}
}
}
.padding()
}
}
}
struct Square: View {
public var width: CGFloat = UIScreen.main.bounds.width / 3 - 20
var body: some View {
Rectangle()
.stroke(Color.black, lineWidth: 2)
.aspectRatio(1, contentMode: .fit)
.frame(width: width)
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。