Grids let you arrange views in rows × columns while preserving SwiftUI’s
declarative style. They balance the straightforwardness of VStack
/HStack
with the performance of collection‑style containers.
Lazy grids (LazyVGrid
/LazyHGrid
) and the new Grid
have different performance profiles—pick the right one for your target OS version.
Grid
& GridRow
Basics
Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 12) {
GridRow {
Text("CPU").bold()
Text("A17 Pro")
Text("6‑core")
}
Divider().gridCellColumns(3) // spans full row
GridRow {
Text("RAM")
Text("8 GB")
Text("LPDDR5")
}
}
.padding()
All cells in a column inherit the grid’s alignment unless overridden. Combine with .frame(maxWidth:.infinity,alignment:.trailing)
for numeric tables.
LazyVGrid
& LazyHGrid
Cells are created on‑demand as they scroll into view within a ScrollView
, reducing memory usage for long lists.
.fixed(CGFloat)
– fixed width / height.flexible(min:CGFloat?, max:CGFloat?)
.adaptive(min:CGFloat, max:CGFloat? = nil)
let columns = [
GridItem(.adaptive(min: 80), spacing: 12)
]
ScrollView {
LazyVGrid(columns: columns, spacing: 16) {
ForEach(0..<100) { index in
RoundedRectangle(cornerRadius: 12)
.fill(.blue.opacity(0.7))
.aspectRatio(1, contentMode: .fit)
.overlay(Text("\(index)").foregroundColor(.white))
}
}
.padding()
}
Use pinnedViews to pin headers/footers when mixing Section
in Lazy*Grid
.
struct PhotoGrid: View {
let photos:[UIImage]
private var columns:[GridItem] {
[GridItem(.adaptive(min: 100), spacing: 8)]
}
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 8) {
ForEach(photos, id:\.self) { img in
Image(uiImage: img)
.resizable()
.aspectRatio(1, contentMode: .fill)
.clipped()
.cornerRadius(10)
}
}
.padding()
}
}
}
struct MonthView: View {
let days = Calendar.current.shortWeekdaySymbols
let dates:[Date] // computed for the month
var body: some View {
Grid(horizontalSpacing: 4, verticalSpacing: 4) {
// weekday headers
GridRow {
ForEach(days, id:\.self){ Text($0).font(.caption2).bold() }
}
// dates
ForEach(dates, id:\.self) { date in
GridRow {
Text(Calendar.current.component(.day, from: date).description)
.frame(maxWidth:.infinity)
.padding(6)
.background(.thinMaterial)
.cornerRadius(4)
}
}
}
}
}
Measure a cell with GeometryReader
to size content proportionally (e.g., square thumbnails).
Lazy*Grid
for large, scrollable content.Grid
is often simpler & faster.NSGridView
let grid = NSGridView(views: [
[NSTextField(labelWithString:"CPU"), NSTextField(labelWithString:"M3 Max")],
[NSTextField(labelWithString:"Cores"), NSTextField(labelWithString:"40‑core GPU")]
])
grid.rowSpacing = 8
grid.columnSpacing = 12
grid.yPlacement = .center
Unlike SwiftUI grids, NSGridView
relies on Auto Layout constraints and is not lazy‑loaded. Wrap it in NSViewRepresentable
for use inside SwiftUI.
Grid
(iOS 16+), Lazy*Grid
(iOS 14+).ScrollView
for vertical/horizontal paging when content might overflow.