【iOS/SwiftUI】SwiftUIでCollectionViewを実装

目次

概要

SwiftUIで縦横にマス目状のUIを設置する方法を調べて実装してみた。

ソースコード

アプリ実行部分

import SwiftUI

@main
struct TestApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            PanelScrollView()
        }
    }
}

View表示部分

import SwiftUI

struct Symbol: Identifiable {
    var id = UUID()
    var image: String
}

struct PanelScrollView: View {
    let imageNames: [Symbol] = [Symbol(image: "man1"), Symbol(image: "man2"),
                                Symbol(image: "man3"), Symbol(image: "man4"),
                                Symbol(image: "man5"), Symbol(image: "man6"),
                                Symbol(image: "man7"), Symbol(image: "man8"),
                                Symbol(image: "man9"),
                                Symbol(image: "pin1"), Symbol(image: "pin2"),
                                Symbol(image: "pin3"), Symbol(image: "pin4"),
                                Symbol(image: "pin5"), Symbol(image: "pin6"),
                                Symbol(image: "pin7"), Symbol(image: "pin8"),
                                Symbol(image: "pin9"),
                                Symbol(image: "sou1"), Symbol(image: "sou2"),
                                Symbol(image: "sou3"), Symbol(image: "sou4"),
                                Symbol(image: "sou5"), Symbol(image: "sou6"),
                                Symbol(image: "sou7"), Symbol(image: "sou8"),
                                Symbol(image: "sou9"),
                                Symbol(image: "z1"), Symbol(image: "z2"),
                                Symbol(image: "z3"), Symbol(image: "z4"),
                                Symbol(image: "z5"), Symbol(image: "z6"),
                                Symbol(image: "z7"), ]
    
    let columns: [GridItem] = [GridItem(.adaptive(minimum: 150, maximum: 200))]
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(imageNames) { imageName in
                    ZStack {
                        Color.green
                        VStack {
                            Image(imageName.image)
                        }
                    }
                }
            }
        }
    }
}

デモ動画

詳細

いくつかの要素から成り立っているが、今回のメインの部分はこちらだ。

let columns: [GridItem] = [GridItem(.adaptive(minimum: 150, maximum: 200))]

ScrollView {
    LazyVGrid(columns: columns) {
        ForEach(imageNames) { imageName in
            ZStack {
                Color.green
                VStack {
                    Image(imageName.image)
                }
            }
        }
    }
}

ScrollView

まず、このScrollViewの中に書いていくことで画面に収まらないUIをスクロールで表示できるようになる。

LazyVGrid

これはマス目状にUIを配置することができるUIのこと。
LazyVGridは左から右へUIを並べていって、UIが右端までいったら改行してまた左から右へ並べていく。
こうすることでCollectionViewのようにGrid状(マス目状)に並べることができる。

もし上から下に並べたい場合は以下のようにLazyHGridを使う。

var body: some View {
    ScrollView(.horizontal) {
        LazyHGrid(rows: columns) {
            ForEach(imageNames) { imageName in
                ZStack {
                    Color.green
                    HStack {
                        Image(imageName.image)
                    }
                }
            }
        }
    }
}

細かい変更点は以下の通り。

  • ScrollViewのスクロール方向として「.horizontal」を設定する
  • ScrollViewの直下に「LazyHGrid」を設置する。また引数名は「rows」
  • ForRach文の中のUIはHStackで横並びに配置する

GridItem

これは並べるUIの大きさや各UIのレイアウトの設定を行う。

引数名内容
size各UIの大きさ
spacing各UIとUIの隙間
alignment各UI内部の配置(中央寄せなど)

また、サイズの方法はいくつかあるが、fixを使うとサイズ固定できて、今回のようにadaptiveを使うとサイズが違くても詰めるように配置されるようだ。

参考ページ