iosswiftuilazyvstack

Break a LazyVGrid into pieces


I have the following grid made in SwiftUI with this code:

let columnGrid = [GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0),
                                  GridItem(.fixed(boxWidth), spacing: 0)]

LazyVGrid(columns: columnGrid, spacing: 0) {
                        ForEach((0...80), id: \.self) {
                            Text("\(positions[$0])")
                                .font(.system(size: 27))
                                .frame(width: boxWidth, height: boxWidth)
                                .background(Rectangle().stroke(lineWidth: 0.5))
                        }
                    }

How can I break the grid into pieces? For example, break the grid into groups of 4 blocks.

a b     e g     i j
c d     f h     k l

m n     q r
o p     s t

etc.

Every time I try a combination of LazyVGrid or a massive amount of HStacks and VStacks, it seems super bloated.

I also tried pinned headers with sections but it could only break things up into rows. I want it to break into rows and columns.

Is there a simple way to do this in SwiftUI?

A grid made with LazyVStack


Solution

  • What you are really attempting to do is put a Grid inside of a Grid. With the output you have demonstrated, you want a LazyVGrid inside of a LazyHGrid. The most difficult part will be chunking your data, not the view itself. That can be achieved like this as an example:

    enter image description here

    struct LazyVGridInLazyHGridView: View {
        
        @StateObject var vm = LazyVGridInLazyVGridViewModel()
        
        let gridsColumn = [GridItem(.flexible(), spacing: 0), GridItem(.flexible(), spacing: 0)]
        let boxColumn = [GridItem(.fixed(30), spacing: 0), GridItem(.fixed(30), spacing: 0)]
        
        var body: some View {
            LazyHGrid(rows: gridsColumn, spacing: 15) {
                ForEach(vm.data, id: \.self) { box in
                    LazyVGrid(columns: boxColumn, spacing: 15) {
                        ForEach(box) { item in
                            Text(item.name)
                        }
                    }
                    .background(Color.gray.opacity(0.15))
                }
            }
            .frame(height: 150)
        }
    }
    
    struct VGridDataModel: Identifiable, Hashable {
        let id = UUID()
        var name: String
    }
    
    class LazyVGridInLazyVGridViewModel: ObservableObject {
        @Published var data: [[VGridDataModel]] = []
        
        init() {
            for strideIndex in stride(from: 1, to: 20, by: 4) {
                data.append(Array(strideIndex..<(strideIndex + 4)).map({ VGridDataModel(name: $0.description) } ))
            }
        }
    }