LazyHGrid in SwiftUI

DevTechie Inc
Jun 17, 2022


Photo by Brands&People on Unsplash

LazyHGrid is a container view that arranges its child views in a grid that grows horizontally, creating items only as needed.

Lazy grid mean that the grid view does not create items until they are needed.

Let’s start with a simple LazyHGrid. Horizontal grid needs row item of type GridItem so we will create simplest GridItem possible:

let rows = [GridItem()]
We will use this rows property while initializing LazyHGrid. One of the initializer for this grid takes rows and viewBuilder closure as the parameter.

LazyHGrid(rows: <#T##[GridItem]#>, content: <#T##() -> _#>)
Let’s put all of this together:

struct LazyHGridExample: View {
    let rows = [GridItem()]
    var body: some View {
        LazyHGrid(rows: rows) {   
            Text("DevTechie,")
            Text("Learn by example")
        }
    }
}
Just like HStack or Group control, we can set common properties at the container level. We will add font and foregroundColor to our grid.

struct LazyHGridExample: View {
    let rows = [GridItem()]
    var body: some View {
        LazyHGrid(rows: rows) {   
            Text("DevTechie,")
            Text("Learn by example")
        }
        .font(.title)
        .foregroundColor(.orange)
    }
}
Let’s add another row to the grid.

struct LazyHGridExample: View {
    let rows = [GridItem(), GridItem()]
    var body: some View {
        LazyHGrid(rows: rows) {   
            Text("DevTechie,")
            Text("Learn by example")
        }
        .font(.title)
        .foregroundColor(.orange)
    }
}
How about a few more rows?

struct LazyHGridExample: View {
    let rows = [GridItem(), GridItem(), GridItem(), GridItem(), GridItem(), GridItem()]
    var body: some View {
        LazyHGrid(rows: rows) {   
            Text("DevTechie,")
            Text("Learn by example")
            Text("SwiftUI")
            Text("iOS Development")
            Text("Machine Learning")
            Text("Natural Language Processing")
        }
        .font(.title)
        .foregroundColor(.orange)
    }
}
Notice the size of grid. LazyHGrid takes as much space as it has been given by its parent but as more rows are added, grid makes the space available for other rows to fit in.
Spacing in LazyHGrid
Spacing parameter defined in LazyHGrid is applied between items in a row:

struct LazyHGridExample: View {
    let rows = [GridItem()]
    var body: some View {
        LazyHGrid(rows: rows, spacing: 40) {   
            Text("DevTechie")
            Text("Learn by Example")
        }
        .font(.title)
        .foregroundColor(.orange)
    }
}
Use GridItem’s spacing parameter, if you like to add spacing between rows
Fixed Cell for LazyHGrid
We can set cell size for items in row with the help of GridItem.size.fixed(CGFloat:) item type as shown below:

struct LazyHGridExample: View {
    let rows = [GridItem(.fixed(100)), GridItem(.fixed(100))]
    var body: some View {
        LazyHGrid(rows: rows, spacing: 40) {   
            Image(systemName: "heart")
                .padding()
                .background(Color.blue)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            
            Image(systemName: "rectangle")
                .padding()
                .background(Color.pink)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            
            Image(systemName: "circle")
                .padding()
                .background(Color.green)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            Image(systemName: "square")
                .padding()
                .background(Color.orange)
                .frame(maxWidth: 100)
                .clipShape(Circle())
        }
        .font(.largeTitle)
        .foregroundColor(.white)
    }
}
Flexible Cell for LazyHGrid
Flexible is the default value for a GridItem so when we are creating GridItem without any parameter during initialization, item is created with flexible sizing. We use flexible option to set minimum and maximum size for item cell. Maximum is an optional parameter.

struct LazyHGridExample: View {
    let rows = [GridItem(.flexible(minimum: 20, maximum: 50)), GridItem(.flexible(minimum: 50))]
    var body: some View {
        LazyHGrid(rows: rows, spacing: 40) {   
            Image(systemName: "heart")
                .padding()
                .background(Color.blue)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            
            Image(systemName: "rectangle")
                .padding()
                .background(Color.pink)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            
            Image(systemName: "circle")
                .padding()
                .background(Color.green)
                .frame(maxWidth: 100)
                .clipShape(Circle())
            Image(systemName: "square")
                .padding()
                .background(Color.orange)
                .frame(maxWidth: 100)
                .clipShape(Circle())
        }
        .font(.largeTitle)
        .foregroundColor(.white)
    }
}
Adaptive Size for LazyHGrid
If you are looking for your grid to create rows based on the available space then you need adaptive type of GridItem.

struct LazyHGridExample: View {
    let rows = [GridItem(.adaptive(minimum: 100))]
    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, spacing: 40) {   
                ForEach(1...30, id: \.self) { idx in 
                    Image(systemName: "\(idx).circle")
                        .padding()
                        .background(Color(hue: Double.random(in: 0...1), saturation: Double.random(in: 0...1), brightness: Double.random(in: 0...1)))
                        .clipShape(Circle())
                }
            }
            .font(.largeTitle)
            .foregroundColor(.white)
        }
    }
}
Alignment
Vertical alignment for the row can be controlled with the help of alignment parameter for GridItem:

struct LazyHGridExample: View {
    let rows = [GridItem(.adaptive(minimum: 100), alignment: .top)]
    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, spacing: 40) {   
                ForEach(1...30, id: \.self) { idx in 
                    Image(systemName: "\(idx).circle")
                        .padding()
                        .background(Color(hue: Double.random(in: 0...1), saturation: Double.random(in: 0...1), brightness: Double.random(in: 0...1)))
                        .clipShape(Circle())
                }
            }
            .font(.largeTitle)
            .foregroundColor(.white)
        }
    }
}
Pinned Views
Just like LazyVGrid, LazyHGrid also supports pinned views.

struct LazyHGridExample: View {
    let rows = [GridItem(.adaptive(minimum: 200), alignment: .top)]
    var body: some View {
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, spacing: 40, pinnedViews: [.sectionHeaders]) {
                Section {
                    ForEach(1...30, id: \.self) { idx in
                        Image(systemName: "\(idx).circle")
                            .padding()
                            .background(Color(hue: Double.random(in: 0...1), saturation: Double.random(in: 0...1), brightness: Double.random(in: 0...1)))
                            .clipShape(Circle())
                    }
                } header: {
                    VStack {
                        ForEach(Array("DevTechie"), id:\.self) { char in
                            Text(String(char))
                                .padding(.horizontal)
                        }
                    }.foregroundColor(.black)
                        .frame(maxHeight: .infinity)
                        .background(.thinMaterial)
                        
                }
                
            }
            .font(.largeTitle)
            .foregroundColor(.white)
        }
    }
}
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to subscribe our weekly newsletter at https://www.devtechie.com