Mastering the Grid in SwiftUI





Fireworks, habr. Before we move on to the article, I want to share with you absolutely free of charge the recording of two very useful lessons that our teachers gave in anticipation of the start of the basic and advanced courses on iOS development:



  1. A quick start to iOS development
  2. Making a multi-threaded Kotlin Multiplatform application


Now let's move on to the article.






This week, I want to talk to you about Grids, one of the most anticipated innovations in SwiftUI. Everyone was eagerly awaiting an alternative UICollectionViewin SwiftUI, and finally it came out this year. SwiftUI provides us with LazyVGrid and LazyHGrid views that we can use to create layouts with grids of items.



The basics



LazyVGrid and LazyHGrid are two new View types that SwiftUI provides us to create a super custom Layout based on a grid of items. The only difference between them is the fill axis. The LazyVGrid fills the available space vertically. LazyHGrid places its children horizontally. The axis is the only difference between these two views. Therefore, everything you learn about LazyVGrid applies to LazyHGrid and vice versa. Let's take a look at the first example.



struct ContentView: View {
    private var columns: [GridItem] = [
        GridItem(.fixed(100), spacing: 16),
        GridItem(.fixed(100), spacing: 16),
        GridItem(.fixed(100), spacing: 16)
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(
                columns: columns,
                alignment: .center,
                spacing: 16,
                pinnedViews: [.sectionHeaders, .sectionFooters]
            ) {
                Section(header: Text("Section 1").font(.title)) {
                    ForEach(0...10, id: \.self) { index in
                        Color.random
                    }
                }

                Section(header: Text("Section 2").font(.title)) {
                    ForEach(11...20, id: \.self) { index in
                        Color.random
                    }
                }
            }
        }
    }
}






In the above example, we are creating a three column grid where each column is a fixed size of 100pt. I'm going to use this example to describe all the configuration options available to us.



  1. The parameter columnsis an array that defines the columns in the grid layout. To describe a column, SwiftUI provides us with the GridItem type . We'll talk about it a little later.
  2. The parameter alignmentallows us to align the contents of the grid using an enumeration HorizontalAlignmentfor LazyVGrid and VerticalAlignmentfor LazyHGrid . Works the same as stack alignment.
  3. The parameter spacingspecifies the distance between each row inside the LazyVGrid or the space between each column inside the LazyHGrid .
  4. The parameter pinnedViewsallows you to specify options for pinning section headers and footers. It is empty by default, which means that headers and footers behave like content and disappear on scrolling. You can enable pinning of the header and footer, in which case they will overlap with the content and become permanently visible.


GridItem



Each column in the grid must be defined with a structure GridItem. The type GridItemallows us to specify the size, alignment and spacing for each column. Let's take a look at a small example.



private var columns: [GridItem] = [
    GridItem(.fixed(50), spacing: 16, alignment: .leading),
    GridItem(.fixed(75)),
    GridItem(.fixed(100))
]






As you can see, each column can have different size, spacing, and alignment options. The most interesting thing here is the size. There are three ways to determine the size of a column within a grid. It can be fixed, flexible, or adaptive.



The Fixed column is the most obvious one. The grid places the column according to the size you specify. In the previous example, we created a three-column layout in which the columns are fixed at 50pt, 75pt, and 100pt, respectively.



option flexibleallows you to define a column that expands or contracts based on the available space. We can also provide minimum and maximum flexible column sizes. By default it uses a minimum value of 10pt and is not capped at the maximum.



private var columns: [GridItem] = [
    GridItem(.flexible(minimum: 250)),
    GridItem(.flexible())
]






Here we are creating a layout that divides the available space between two flexible columns. The first column takes up 250pt of its minimum size, while the second has all the rest of the available space.



The most interesting option is adaptive . The responsive option allows us to place multiple elements in the space of a single flexible column. Let's try to figure it out with an example.



private var columns: [GridItem] = [
    GridItem(.adaptive(minimum: 50, maximum: 100)),
    GridItem(.adaptive(minimum: 150))
]






As you can see, we have two responsive columns. The first column contains several elements with a minimum size of 50pt and a maximum of 100pt. Responsive columns are useful when the number of items within a column needs to be based on the available space.



The real power of grids comes when you start mixing column types. You can create a two-column layout, where the first is fixed and the second is responsive. Let's see how it will look.



private var columns: [GridItem] = [
    GridItem(.fixed(100)),
    GridItem(.adaptive(minimum: 50))
]






Conclusion



The grid allows you to create very complex and interesting layouts by mixing different types GridItem. It should be noted that all changes to the meshes can be animated. I hope you enjoyed this article. Feel free to follow me on Twitter and ask your questions related to this topic. Thank you for your attention, see you!






You can find out more about our courses using the links below:









All Articles