Are you looking for a powerful tool to neatly arrange your views in a table-like layout? Look no further than the SwiftUI Grid. In this tutorial, we will explore the capabilities of the SwiftUI Grid and learn how to implement it in your projects.
But first, let’s briefly touch upon the differences between various SwiftUI layout components. If you’re interested in a comprehensive overview, check out my article “SwiftUI Layout Overview: When to Use List, VStack, Grids, etc.” It delves into the details of each component and helps you understand their unique strengths.
Now, let’s focus on the SwiftUI Grid. Unlike its lazy counterparts, the Grid is perfect for small, static lists. It simplifies the alignment of multiple columns and ensures a consistent and organized presentation of data.
To get started, we’ll walk through the process of setting up your first Grid. Then, we’ll explore how to align content within Grid rows, allowing for custom column alignments. Along the way, we’ll dive into real-world examples, such as a user information table and a weather forecast layout, to demonstrate the Grid’s versatility.
By the end of this tutorial, you’ll have a solid understanding of how to implement and utilize the SwiftUI Grid effectively in your projects. So, let’s dive in and unlock the power of the SwiftUI Grid for your app’s layout needs.
What is the SwiftUI Grid?
The SwiftUI Grid is a layout component that allows developers to arrange visual elements in a structured, table-like format. Think of it as a way to organize your app’s interface into neat rows and columns, much like a spreadsheet or a traditional HTML table.
Unlike some other layout components that are designed to handle large, dynamic lists of data efficiently (such as `LazyVGrid`), the SwiftUI Grid is not lazy-loaded. This means that it doesn’t wait until the last moment to render its content. Instead, it renders all of its children immediately, which makes it particularly well-suited for displaying smaller, static collections of views where performance isn’t a major concern.
On macOS and iPadOS you have an alternative with is SwiftUI Table. This is not available for the iPhone
In essence, the SwiftUI Grid is a straightforward and effective tool for developers who need to create a clean, organized presentation of data or controls within their app, without the overhead of handling large datasets or complex, scrollable lists. It’s a component that prioritizes simplicity and order, ensuring that each element is precisely where it should be in the grid’s structure.
Setting Up Your First Grid
Creating a grid layout in SwiftUI is a straightforward process that allows you to organize your views in a structured manner.
Define Your Data
To get started, let’s set up a basic grid using a simple data model. We’ll use the following Item
struct as our example data:
struct Item: Identifiable {
let id = UUID()
var item: String
var description: String
var quantity: Int = 1
var price: Double = 0
}
This struct represents an item with a unique identifier, a name, a description, a quantity, and a price. Now, let’s create a grid that displays a list of these items.
First, we need to define an array of Item
objects that we want to display in our grid:
import SwiftUI
struct ContentView: View {
let items = [Item(item: "Apple",
description: "Juicy green apple",
quantity: 3,
price: 1.99),
Item(item: "Orange",
description: "Sweet and tangy orange",
quantity: 5,
price: 2.49),
Item(item: "Banana",
description: "Fresh yellow banana",
quantity: 2,
price: 0.99)]
var body: some View {
//...
}
}
Initialize the Grid
Next, I’ll create a SwiftUI view that contains our grid. I will use the Grid
view to arrange our items in rows and columns:
struct ContentView: View {
let items = ...
var body: some View {
Grid {
ForEach(items) { item in
GridRow {
Text(item.item)
.bold()
Text(item.description)
Text("Qty: \(item.quantity)")
Text(String(format: "$%.2f", item.price))
}
}
}
.padding()
}
}
In this code snippet, we’re using a ForEach
loop to iterate over each Item
in our items
array. For each item, we create a GridRow
that contains four text views: one for the item name, one for the description, one for the quantity, and one for the price.
The size of each column is defined by the largest cell in that column. The ´Quantity´ cells have the smallest width and are thus the narrowest column. SwiftUI automatically tracks all cells and their width.
Adding Column Headings to the Grid
To make our grid more readable and to give it a table-like appearance, we can add headings for each column. This will help users understand the data they’re looking at. Here’s how we can modify our ItemsGridView
to include column headings:
Grid {
// Column Headings
GridRow {
Text("Item")
Text("Description")
Text("Quantity")
Text("Price")
}
.font(.title2)
// Divider to separate headings from items
Divider()
// Item Rows
ForEach(items) { item in
...
}
}
In the above code snippet, I added a static GridRow
at the top to serve as our column headings. You can also add a Divider
to visually separate the headings from the item rows.
Customizing the Grid Appearance
SwiftUI’s Grid
view is not lazy, which means it’s ideal for small, finite lists where you want precise control over the layout. To further customize the appearance of our grid, we can add spacing and alignment properties.
How to change the Grid Column Alignment?
The above shopping list does not have a good looking alignment. Per default all columns and rows are center aligned. Let´s use the alignment and spacing of the Grid initializer:
Grid(alignment: .leadingFirstTextBaseline,
horizontalSpacing: 15,
verticalSpacing: 10) {
// Column Headings
GridRow {
Text("Item")
Text("Description")
Text("Quantity")
Text("Price")
}
.font(.title2)
// Divider to separate headings from items
Divider()
// Item Rows
ForEach(items) { item in
...
}
}
Now all columns are aligned to the leading edge. But in this case I would prefer the ´Quantity´ column to be center aligned. You can use another modifier for this and add it to the view inside the GridRow:
GridRow(alignment: .bottom) {
Text(item.item)
.bold()
Text(item.description)
Text("Qty: \(item.quantity)")
.gridColumnAlignment(.center)
Text(String(format: "$%.2f", item.price))
}
The header cell for ´Quantitiy´ is still leading aligned, but below it the quantity count is center aligned.
Aligning the Views inside Grid Rows Differently
You can also change the alignment for each GridRow individually:
GridRow(alignment: .bottom) {
Text(item.item)
.bold()
Text(item.description)
Text("Qty: \(item.quantity)")
Text(String(format: "$%.2f", item.price))
}
Managing Empty Cells and Adding a Summary Row
In a grid layout, you might encounter situations where you need to create empty cells to align your content properly. I want to expand the above example and add summary rows that span multiple columns.
If I add a row with the total cost, I am adding on cell that is used for the first column:
Grid(alignment: .leadingFirstTextBaseline,
horizontalSpacing: 15,
verticalSpacing: 10) {
// Column Headings
GridRow {
Text("Item")
Text("Description")
Text("Quantity")
Text("Price")
}
.font(.title2)
// Divider to separate headings from items
Divider()
// Item Rows
ForEach(items) { item in
...
}
Divider()
GridRow {
// Total price cell
Text(String(format: "$%.2f", total))
}
}
This cell will be aligned to the leading edge of the first column and thus grid. But I actually want to add it to the ´Price´ column. Therefor, I need to add empty cells for the first 3 columns:
GridRow {
Color.clear
.gridCellColumns(3)
.gridCellUnsizedAxes(.vertical)
Text(String(format: "$%.2f", total))
}
I am using a Clear color to create an empty cell. Per default this will make the row very large. To constrain the color in the vertical direction, I am using ´.gridCellUnsizedAxes(.vertical)´. Per default, the color would only span one column. You can adjust this with the ´gridCellColumns´ modifier and tell the grid to span the cell over multiple columns.
With these customizations, you can create complex grid layouts that include empty cells, span cells across multiple columns, and add summary rows to display aggregated data. This level of control allows you to design grids that are both functional and visually appealing.
Advance Example: Weather Forecast View
To create a weather forecast view, we’ll use a GridView with horizontal and vertical styles. This allows us to specify alignment, horizontal spacing, and vertical spacing options. We’ll align the weekdays to the leading edge and the numbers to the trailing edge.
struct WeatherForcastView: View {
let forcastData = WeatherData.example()
var body: some View {
GroupBox("10-Day Forcast") {
Grid(alignment: .trailing,
horizontalSpacing: 10,
verticalSpacing: 5) {
ForEach(forcastData) { data in
GridRow(alignment: .center) {
Text(data.weekday.name())
.gridColumnAlignment(.leading)
Image(systemName: data.iconName)
.renderingMode(.original)
.imageScale(.large)
.gridColumnAlignment(.center)
Text(String(data.lowTemperature) + "°")
ProgressView(value: data.progress)
Text(String(data.hightTemperature) + "°")
}
}
}
}
}
}
In this code snippet, we iterate over the weatherData array and create a GridRow for each data point. Iam aligning the weekdays to the leading edge using
.gridColumnAlignment(.leading)
the image icon is aligned in the center:
.gridColumnAlignment(.center)
and use the default alignment for the other views. The gridColumnAlignment modifier allows us to specify a different alignment for a specific column.
Conclusion
create neatly organized views that resemble table-like layouts, perfect for small, non-lazy lists where immediate rendering is beneficial. From setting up your first grid to customizing rows and columns for complex layouts, we’ve covered a range of examples that showcase the Grid’s capabilities.
By now, you should have a solid understanding of how to implement and use the SwiftUI Grid in your own projects. Whether you’re aligning content within grid rows, creating a user information table, designing a weather forecast view, or compiling an expense report grid, the principles we’ve discussed will guide you in achieving a consistent and organized presentation of data.
Remember, the key to mastering any new component is practice. So, I encourage you to take the examples from this tutorial and apply them to your SwiftUI apps. Experiment with different alignments, spacings, and data structures. See how the Grid can enhance the user interface of your applications.
Great tutorial! I’m loving the flexibility of SwiftUI and this guide has helped me understand how to use the Grid system to create a custom layout that fits my needs. The example projects are also super helpful in illustrating the different use cases.Thanks for sharing!
I came across this article and it has been really helpful for the scoreboard I need in my game app, thanks a lot!!