Exploring Freelancing
Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!
- Grid layouts in Swift
- SwiftUI grid layout example
GridItem
LazyVGrid
LazyHGrid
PinnedScrollableViews
- Conclusion
Originally written for LogRocket, a modern frontend monitoring and product analytics solution. Link to the article - Understanding the SwiftUI grid layout
Before they were introduced during Apple’s 2020 Worldwide Developer’s Conference, grids were among the most-desired features to be included in SwiftUI. Up to that point, many developers came up with their implementation to approximate UICollectionView
in SwiftUI. Then the Swift team officially introduced the LazyVGrid
and LazyHGrid
layouts at WWDC 2020.
In this tutorial, we’ll go over the basics of the SwiftUI grid layout. We’ll demonstrate how to create grids with SwiftUI by developing a reminder app that helps you categorize your reminders with a due date and mark them complete.
To follow along, you should have basic knowledge of:
- SwiftUI
- Stacks
- Observable object
- ScrollViews
Grid layouts in Swift
A grid layout can be seen in almost all Apple applications. You may have noticed it in the Photos app or the Calendar app. It helps to accommodate more vital data into the same space by splitting the views into rows and columns.
Take a look at the examples below:
SwiftUI grid layout example
To demonstrate how the SwiftUI grid layout works, we’ll build a reminder app. We’ll start with a project with all the boiler code already written.
The app contains a main screen on which to implement grids. To add new reminders or categories, you can click the Add button in the top-right. The top-left button will switch between a vertical and horizontal layout to give users some control over the display.
The app already contains a model for the categories and the reminder with the name, due date, and a boolean value to mark them as completed. The view model has methods to add more reminders or update the status of the reminder. The app uses test data for convenience.
With all that in mind, let’s jump into the theory of how grids work in Swift and how they are different from standard lists.
GridItem
In a grid layout in SwiftUI, each element is called GridItem
. We can customize it by changing its size, spacing between, and aligning it to the parent view.
There are three types of GridItem
:
- Fixed — The element is fixed in size no matter the orientation or screen size of the device
- Flexible — The element is flexible enough to resize itself according to the space available
- Adaptive — The element can adapt to the screen size or orientation, with a minimum width or height provided. For example, it can be two columns on iPhone, but on iPad, it adapts to the given size and makes it three columns
These types differ according to how they are used, either in a vertical grid or a horizontal grid.
We start with a simple array of fixed grid items with two columns and rows. Now let’s add the following code under style
in ReminderView
:
This creates two grid items of a fixed size of 120
in a row or a column depending upon what we use.
You can similarly create flexible items. These items take the space available to fill two columns or rows:
Likewise, you can create adaptive items:
If the space available with a minimum size of 120
is enough for three or four rows/columns, the items adjust automatically.
With the basics done, it’s time to fill these items in a grid!
LazyVGrid
[LazyVGrid](https://developer.apple.com/documentation/swiftui/lazyvgrid)
is a container view that arranges its child views in a grid that grows vertically, creating items only as needed.
The vertical grid can be divided into multiple columns as per your requirement. The API gives the flexibility to fix the element’s size or make it either flexible or adaptive.
LazyVGrid
contains the following parameters for customization: the column to position each item, alignment in the view, the spacing between grid and next item in the view, and pinned views to bound to the scroll view.
We’ll start by adding a vertical scroll view that will house the grid. Then, we’ll add LazyVGrid
with the columns as the first parameter.
Replace the content below style
in ReminderView
with the following:
This produces a simple grid with just few lines of code:
Turn over to landscape orientation, and the grid automatically adapts to more than two columns:
Now that we have a pretty vertical grid, it’s time to modify it to create a nice horizontal one.
LazyHGrid
The horizontal grid can be divided into multiple rows. The view performs similar functionality to LazyVGrid
.
LazyHGrid
contains similar parameters for customization: the row to position each item, alignment in the view, the spacing between grid and next item in the view, and pinned views to bound to the scroll view.
Add a switch case on style
below ForEach()
to distinguish between the vertical and horizontal layout:
We created fixed-size items for the horizontal layout. Replace the old implementation of items
with:
Now let’s add a horizontal scroll view that will house the grid. Then, add LazyHGrid
with the rows as the first parameter.
Replace the content below case .horizontal
in the switch case with the folllowing:
Running the application shows a list of grids that can be scrolled horizontally:
Try adding new reminders under different categories of urgent, important, and casual. We find that all of them are added under a simple grid with no header to distinguish them. Now we need need headings for the categories.
PinnedScrollableViews
PinnedScrollableViews
are lists of headers that “pin” **below the navigation title while scrolling. It can be used to create a sticky effect for the header.
As a practical example, if you have many reminders in a particular category, it would be cool to have the reminder category pinned at the top while scrolling so the user knows under which type they’re looking at the reminders.
Similarly, you can pin the footers of the view that stick to the bottom while scrolling.
Let’s implement pinning of headers in our app.
Add the pinnedViews
parameter to both LazyVGrid
and LazyHGrid
, which provides the array of pinned scrollable views. In this case, it would be [.sectionHeaders]
.
Now, we wrap remindersView(category:)
inside a Section
and create a headerView
for it. The headerView
takes the reminder category name as the parameter.
private func categoryVHeader(with header: String) -> some View {
Text(header)
.font(.title2)
.bold()
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.background(RoundedRectangle(cornerRadius: 0)
.fill(Color.headerBackground))
}
The complete code for our LazyVGrid
implementation looks like this:
Now let’s say want something more remarkable for the horizontal grid with the header flipped 90 degrees and sticking to the leading side of the screen.
Now the code for our LazyHGrid
implementation looks like this:
Try tapping the layout button on the top left of the screen to see your upcoming reminders in different grid layouts.
The app uses test data for our convenience. To use it for your own work, initialize an empty array of reminderCategories
in RemindersViewModel
:
Conclusion
Grids are appropriate for showing more essential data, such as photos or album art, in less space. SwiftUI 2.0 makes it easier to create simple grid layouts. I’m hoping for more complex functionality in the future.
As a next step, you could try to recreate the photos app grid layout or create something similar to the reminders app for fun.
Exploring Freelancing
Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!