【Swift UI】グリッドレイアウトの実装方法!LazyVGridとGridItemの使い方

【Swift UI】グリッドレイアウトの実装方法!LazyVGridとGridItemの使い方

この記事からわかること

  • SwiftUIグリッドレイアウト実装する方法
  • LazyVGridGridItem使い方
  • グリッドレイアウト個数余白調整

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

SwiftUIを使ってグリッドレイアウトを簡単に実装できるLazyVGridとGridItemの使い方をまとめていきます。

SwiftUIで実装できるグリッドレイアウト

グリッドレイアウトとはWebサイトなどのデザインの1つで格子状に分割され、ブロックを並べたようにコンテンツを配置する手法のことです。

SwiftUIでは以下のようなグリッドレイアウトを簡単に実装することができます。

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)
            }
        }
    }
}
LazyHGridとLazyVGridを使って
グリッドレイアウトを実装したスクリーンショット

同様に横に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要素を格納した配列の要素数を変化させることで列数(行数)の調整が可能になります。

グリッドレイアウトを実装するポイント

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)
            }
        }
    }
}

カスタムグリッドレイアウト

通常のグリッドレイアウトではなく行と列を跨ぐようなアイテムの絡んだグリッドレイアウトを実装したくなりました。しかしこれがなかなか思うように実装できず、LazyVGridGridなどを使用した方法では期待通りにできませんでした。

SwiftUIで実装できるグリッドレイアウトの例

結論HStackVStackを使用して力技での実装になりましたので一応コードを添付しておきます。良い方法があったらお問い合わせより教えてください。

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)
    }
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index