VStack, HStack, ZStack
SwiftUI's layout system starts with stacks. VStack arranges views vertically, HStack horizontally, and ZStack layers them on top of each other. These three containers handle most layout needs.
VStack(spacing: 12) {
Text("Top")
Text("Middle")
Text("Bottom")
}
HStack(spacing: 12) {
Image(systemName: "star")
Text("Favorite")
Spacer()
Text("42")
}
ZStack {
Color.blue
Text("Overlaid")
.foregroundColor(.white)
}
Try it Yourself ->
Spacer for Flexible Space
A Spacer expands to fill available space. Put one between elements to push them apart. In an HStack, it pushes items to the edges. In a VStack, it creates vertical breathing room.
HStack {
Text("Left")
Spacer()
Text("Right")
}
VStack {
Text("Top")
Spacer()
Text("Bottom")
}
.frame(height: 200)
Try it Yourself ->
Divider for Separators
Draw a thin line between views with Divider(). It takes up the full width of its container and is perfect for visually separating sections.
VStack(alignment: .leading, spacing: 0) {
Text("Section 1")
.padding()
Divider()
Text("Section 2")
.padding()
Divider()
Text("Section 3")
.padding()
}
Try it Yourself ->
ScrollView for Scrollable Content
When content exceeds the screen, wrap it in a ScrollView. It scrolls vertically by default, or use .horizontal for horizontal scrolling. Combine with VStack for vertical scrollable lists.
ScrollView {
VStack(spacing: 16) {
ForEach(1..<50) { i in
Text("Item \(i)")
.frame(maxWidth: .infinity)
.padding()
.background(Color(.systemGray6))
.cornerRadius(8)
}
}
.padding()
}
Try it Yourself ->
LazyVStack and LazyHStack
Regular stacks create all their views at once. Lazy stacks only create views when they're about to appear on screen. For long lists, lazy stacks are much more efficient and use way less memory.
ScrollView {
LazyVStack(spacing: 8) {
ForEach(1..<1000) { i in
HStack {
Text("Row \(i)")
Spacer()
Image(systemName: "chevron.right")
}
.padding()
.background(Color(.systemBackground))
}
}
}
Try it Yourself ->
Grid for Two-Dimensional Layouts
The Grid view arranges items in rows and columns. Each row can have different column counts, and items align across rows. Great for dashboards, galleries, and settings screens.
Grid(alignment: .leading, horizontalSpacing: 16, verticalSpacing: 16) {
GridRow {
Color.red.frame(width: 80, height: 80)
Color.green.frame(width: 80, height: 80)
Color.blue.frame(width: 80, height: 80)
}
GridRow {
Color.orange.frame(width: 80, height: 80)
Color.purple.frame(width: 160, height: 80)
}
}
Try it Yourself ->
GeometryReader for Size Info
Sometimes you need to know the size of a view. GeometryReader gives you access to the available space. Use it to create responsive layouts that adapt to any screen size.
GeometryReader { geometry in
VStack {
Text("Width: \(Int(geometry.size.width))")
Text("Height: \(Int(geometry.size.height))")
HStack(spacing: 0) {
Color.red
.frame(width: geometry.size.width * 0.3)
Color.blue
.frame(width: geometry.size.width * 0.7)
}
.frame(height: 50)
}
}
Try it Yourself ->