Labs ICT
⭐ Pro Login

SwiftUI Layout

Stacks, grids, and scroll views.

2 min read | Swift Tutorial
⭐

Want the full learning experience?

Get structured courses, certificates, projects, and instructor support with LabsICT Pro.

Explore Pro Courses

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)
}

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)

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()
}

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()
}

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))
        }
    }
}

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)
    }
}

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)
    }
}