SwiftUI LazyVGrid & LazyHGrid: Implementing Grid Collection Views

Diving into SwiftUI’s LazyVGrid and LazyHGrid, you can create intricate grid layouts that are both efficient and visually appealing. Unlike a typical grid view, LazyVGrid and LazyHGrid offer more dynamic and flexible ways to display content. They are ideal for situations like image galleries, where you need to present data in multiple rows or columns, adapting responsively to different screen sizes and orientations. In this introduction, I’ll guide you through the essentials of using LazyVGrid and LazyHGrid, illustrating how they differ from standard grid views. For a comprehensive understanding of grid views, you might find my previous post, “SwiftUI Grid Tutorial: Neat Rows & Custom Column Alignments,” particularly useful. Let’s delve into the world of SwiftUI LazyVGrid and LazyHGrid and unlock their potential in your iOS apps.

Swiftui Xcode library with Lazyvgrid and lazyhgrid

The Basics of LazyVGrid

Understanding SwiftUI’s LazyVGrid begins with grasping how it efficiently organizes and presents data in a grid format. To illustrate this, let’s use a practical example involving a struct named Emoji. This struct encapsulates the properties of an emoji, including its Unicode scalar value, a string representation, and a unique identifier. Here’s a look at the struct:

struct Emoji: Identifiable {
    let value: Int
    
    var emojiString: String {
        guard let scalar = UnicodeScalar(value) else { return "?" }
        return String(Character(scalar))
    }
    
    var id: Int {
        return value
    }
    
    static func examples() -> [Emoji] {
        let values = 0x1f600...0x1f64f
        return values.map { Emoji(value: $0) }
    }
}

In the Emoji struct, each emoji is identified by its Unicode value, and the emojiString computed property converts this value into a visible emoji character. Next I will create a subview that shows the cell for each Emoji. I am adding a grey background to highlight how large each cell in the grid will be:

struct EmojiCell: View {
    let emoji: Emoji
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 5)
                .fill(Color(white: 0.9))
            Text(emoji.emojiString)
                .font(.system(size: 40))
                .padding()
        }
    }
}

Now, let’s focus on implementing a LazyVGrid using the Emoji struct. LazyVGrid requires you to define the columns and their behaviors. For instance, an adaptive grid item type allows the grid to adjust the number of columns based on the available space:

import SwiftUI

struct ContentView: View {
    let emojis = Emoji.examples()

    var body: some View {
        ScrollView {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 80))]) {
                ForEach(emojis) { emoji in
                     EmojiCell(emoji: emoji)
                }
            }
            .padding()
        }
    }
}
Example for swiftui lazyvgrid with adaptive grid items
Example for swiftui lazyvgrid with adaptive grid items in landscape mode

In this example, LazyVGrid uses adaptive columns with a minimum width of 80 points. It arranges the emoji collection into a grid that adapts to the screen size and device orientation. The grid items are spaced with the default system spacing, both vertically and horizontally, ensuring a neat and organized appearance.

The key takeaway here is how LazyVGrid, combined with adaptive grid items, can create a responsive and visually appealing grid layout without the need for complicated calculations or manual adjustments. It’s a tool that significantly simplifies the process of displaying collections in a structured grid format in your SwiftUI applications.

Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

Types of GridItems in LazyVGrid

In SwiftUI’s LazyVGrid, the core component that determines the layout of the grid is the GridItem. Understanding the types of GridItem and their respective behaviors is important for tailoring the grid to your specific needs. There are three primary types of GridItem you can use: .fixed, .flexible, and .adaptive.

  1. Adaptive Grid Items:
    • The .adaptive grid item is key to creating responsive layouts.
    • You specify a minimum size, and the grid adapts to fit as many items as possible across the available space.
    • For example, using .adaptive(minimum: 80, maximum: 150) ensures each item is at least 80 points wide and the grid adjusts based on screen width and orientation.
    • This type is ideal for dynamic content where the number of columns can vary, such as in a photo gallery app.
  2. Fixed Grid Items:
    • A .fixed grid item has a specific size set for each column.
    • If you specify .fixed(150), every column will be exactly 150 points wide.
    • The number of columns is determined by the number of elements in the columns array.
    • This layout is suitable when you need uniformity in your grid, like displaying exactly 4 rows of images in a horizontal scrollview.
  3. Flexible Grid Items:
    • .flexible grid items allow a range of sizes, making them quite versatile.
    • For instance, .flexible(minimum: 50, maximum: 200) lets the grid item size itself within this range, depending on available space.
    • This approach is beneficial when you have content that can benefit from extra space, like text or mixed media content.
    • It’s also useful for creating multi-column layouts that need to adjust to different screen sizes.

In practice, these GridItem types can be mixed and matched in a LazyVGrid to create complex and versatile layouts. For instance, you might use a combination of fixed and flexible grid items to create a layout that has both uniform and dynamic columns. The choice of GridItem type ultimately depends on the content you are displaying and the user experience you want to achieve.

To illustrate, consider an app that displays a range of emoji characters, similar to the Emoji struct from Section 1. You can use adaptive grid items to display the emojis in a responsive grid that adjusts to the screen size, or fixed grid items to present them in a uniform, orderly fashion.

Mastering SwiftUI LazyHGrid

After exploring the LazyVGrid and its GridItem types, you’ll find that mastering SwiftUI’s LazyHGrid follows a similar approach but with a horizontal twist. LazyHGrid is the horizontal counterpart of LazyVGrid, offering a row-based rather than a column-based grid layout.

Just like LazyVGrid, LazyHGrid requires an array of GridItem for its rows. The GridItem configuration in LazyHGrid determines the height and spacing of the rows.Here’s a basic example of LazyHGrid:

struct ContentView: View {
    let emojis = Emoji.examples()

      var body: some View {
          ScrollView(.horizontal) {
              LazyHGrid(rows: [GridItem(.adaptive(minimum: 80))]) {
                  ForEach(emojis) { emoji in
                      EmojiCell(emoji: emoji)
                  }
              }
              .padding()
          }
      }
}

Because of the adaptive GridItem, the whole height of the screen is filled with emojis. Instead, you can use fixed GridItems to show a fixed number of rows. The following example will generate a grid with 3 rows where the first row is 100 points, the second 200 and the last row is 300 points high:

LazyHGrid(rows: [GridItem(.fixed(100)),
                 GridItem(.fixed(200)),
                 GridItem(.fixed(300))]) {
    ...
}

You an combine different types of GridItems or use the following to show a grid with 3 rows of each 100 points high:

LazyHGrid(rows: Array(repeating: GridItem(.fixed(100)),
                      count: 3)) {
  ...
}
Example for swiftui lazyhgrid with adaptive and fixed grid items

Customizing Grid Spacing and Alignment

LazyVGrid and LazyHGrid have different ways to change the spacing between the columns and rows. You can also change the way the GridItems are aligned to each other. Let’s look at some examples.

Adjusting Grid Spacing

Spacing in grid layouts plays a vital role in defining the aesthetics and readability of the content. In LazyVGrid and LazyHGrid, the spacing parameter controls the distance between rows (for LazyVGrid) or columns (for LazyHGrid). For instance, setting spacing: 20 in a LazyVGrid increases the vertical space between the grid’s rows. Here’s a snippet showing how to adjust this spacing:

LazyVGrid(columns: [GridItem(.adaptive(minimum: 80))], spacing: 2) {
    ForEach(emojis) {
        Text($0.emojiString)
    }
}

In this example, each emoji is spaced 20 points apart vertically, creating a cleaner and more spaced-out grid appearance.

You can further refine the grid layout by adjusting the spacing within the GridItem. The spacing parameter in GridItem specifically affects the spacing between columns in LazyVGrid or rows in LazyHGrid.

Column and Row Spacing in GridItem

You can further refine the grid layout by adjusting the spacing within the GridItem. The spacing parameter in GridItem specifically affects the spacing between columns in LazyVGrid or rows in LazyHGrid. This is particularly useful when you need different spacing between grid lines compared to the content’s inner spacing.

LazyHGrid(rows: [GridItem(.fixed(100), spacing: 20),
                 GridItem(.fixed(200), spacing: 80),
                 GridItem(.fixed(300))], 
                 spacing: 2) {
    ForEach(emojis) { emoji in
        EmojiCell(emoji: emoji)
    }
}
changing the spacing of grid items in a LazyHGrid in Swiftui
Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

Changing the Grid Alignment

Alignment in grid layouts impacts how content is positioned within the grid area. In SwiftUI, you can align content in LazyVGrid and LazyHGrid using the alignment parameter. The above examples have GridItems with uniform sizing. Therefor, I need to change the example so we can actually test the alignment options:

LazyHGrid(rows: [GridItem(.fixed(200), spacing: 10),
                 GridItem(.fixed(200)),
                 GridItem(.fixed(200))],
          spacing: 2) {
    ForEach(Array(emojis.enumerated()), id: \.offset) { (index,emoji) in
        Text(emoji.emojiString)
            .font(.system(size: 40))
            .padding(CGFloat(index * 8))
            .background(Color(white: 0.8))
    }
}

You can use the alignment property of LazyHGrid to change the row alignment:

LazyHGrid(rows: [GridItem(.fixed(200), spacing: 10),
                 GridItem(.fixed(200)),
                 GridItem(.fixed(200))],
          alignment: .bottom,
          spacing: 2) {
  ...
}
changing the alignment of grid items in a LazyHGrid in Swiftui

The above alignment is set to bottom. All items in the grid are thus aligned to the bottom edge of each row.

Additionally, you can use the alignment property of the GridItem. In the following example, I am changing the alignment for the first row only to bottomTrailing. All other rows are using the default alignment of center:

LazyHGrid(rows: [GridItem(.fixed(200), 
                          spacing: 10, 
                          alignment: .bottomTrailing),
                 GridItem(.fixed(200)),
                 GridItem(.fixed(200))],
          spacing: 2) {
   ...
}
SwiftUI LazyHGrid with GridItem alignment of bottom

Advanced Example: Image Gallery View

Consider a gallery app where you want to display images in a grid. Using a combination of spacing, alignment, and padding, you can create a layout that showcases the images in an organized and aesthetically pleasing manner.

You can show an adaptive image gallery view in a vertical ScrollView with LazyVGrid:

image gallery view with swiftui lazyvgrid

Typically, you would load images asynchronously with AsyncImage. The following example, load images in a square grid with LazyHGrid. I used a 3 rows of fixed GridItems and a horizontal ScrollView:

image gallery view with swiftui lazyhgrid

You can also use LazyVGrid to create adaptive layouts. In the following I used adaptive GridItems. The minimum and maximum sizes are chosen in a way that in portrait mode one column fits and in landscape mode 2 columns can be fit.

adaptive layout with lazyvgrid in swiftui

Conclusion

SwiftUI’s LazyVGrid and LazyHGrid offer powerful tools for creating dynamic and responsive grid layouts in iOS apps. Starting with the basics of LazyVGrid, we explored how different GridItem types like Adaptive, Fixed, and Flexible can shape your grid’s behavior and appearance. We then delved into LazyHGrid, highlighting its horizontal layout capabilities, which complement the vertical nature of LazyVGrid. The section on customizing grid spacing and alignment emphasized the importance of these elements in enhancing the visual appeal and functionality of your grids. By mastering these grid layouts, you can create diverse and engaging interfaces that are both visually appealing and user-friendly, significantly elevating the user experience in your SwiftUI applications.

2 thoughts on “SwiftUI LazyVGrid & LazyHGrid: Implementing Grid Collection Views”

  1. Great post! I’m loving the new SwiftUI features, and this one in particular is very useful for creating complex grid layouts. The LazyVGrid and LazyHGrid views make it easy to create responsive grids without having to manually manage layouts. Thanks for sharing your insights!

    Reply

Leave a Comment

Subscribe to My Newsletter

Want the latest iOS development trends and insights delivered to your inbox? Subscribe to our newsletter now!

Newsletter Form

New Course Announcement!!!

50% OFF Launch Sale

MacOS Development with SwiftUI