BS
BleepingSwift
Published on

> Centering Views in SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

One of the most common frustrations when starting with SwiftUI is getting views to center the way you expect. You add a VStack, throw in some content, and wonder why it's sitting at the top of the screen instead of the middle. Or you try to center something horizontally and it stubbornly hugs the leading edge. The confusion usually comes from mixing up two different concepts: how views align within a stack versus how a view positions itself within available space.

The Two Types of Alignment

SwiftUI has two distinct alignment mechanisms that serve different purposes, and understanding the difference unlocks most layout puzzles.

Stack alignment controls how sibling views line up relative to each other. When you write VStack(alignment: .center), you're telling the stack to center its children horizontally relative to one another—but the stack itself still sizes to fit its content and positions itself according to its parent.

Frame alignment controls how a view positions itself within the space it's given. When you apply .frame(maxWidth: .infinity, alignment: .center), you're telling the view to expand and then place its content in the center of that expanded space.

Here's the key insight: a VStack with centered alignment doesn't center itself on screen. It centers its children relative to each other, then takes up only as much space as it needs.

Centering a View on Screen

To center a view both horizontally and vertically, you need to give it space to center within. The most straightforward approach uses Spacer views:

var body: some View {
    VStack {
        Spacer()
        Text("Centered")
        Spacer()
    }
    .frame(maxWidth: .infinity)
}

The vertical Spacer views push the content to the middle, and maxWidth: .infinity ensures the stack expands horizontally. Alternatively, you can use frame alignment directly:

var body: some View {
    Text("Centered")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
}

This works because frame defaults to center alignment. The text expands to fill available space, then positions itself in the center.

When Stack Alignment Isn't Enough

Consider this example where you want a label and value to be centered on screen, but left-aligned relative to each other:

var body: some View {
    VStack(alignment: .leading) {
        Text("Username")
            .font(.caption)
            .foregroundStyle(.secondary)
        Text("john_appleseed")
            .font(.title2)
    }
}

The text aligns correctly (caption above the username, both left-aligned), but the whole block sits at the top-leading corner. To center this block on screen while preserving internal alignment:

var body: some View {
    VStack(alignment: .leading) {
        Text("Username")
            .font(.caption)
            .foregroundStyle(.secondary)
        Text("john_appleseed")
            .font(.title2)
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
}

Now the VStack expands to fill available space and centers its content (the left-aligned text block) within that space.

Horizontal Centering in HStacks

The same principle applies horizontally. An HStack with center alignment centers its children vertically relative to each other—it doesn't center them horizontally within the parent.

To push content to the center of an HStack:

HStack {
    Spacer()
    Text("Centered")
    Spacer()
}

Or to center one element while keeping another at the edge, use a ZStack or overlay approach:

HStack {
    Button("Back") { }
    Spacer()
    Text("Title")
    Spacer()
    Button("Back") { }
        .hidden() // Balances the layout
}

GeometryReader for Precise Positioning

When you need exact positioning relative to the screen or parent, GeometryReader provides the dimensions you need:

GeometryReader { geometry in
    Text("Centered")
        .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
}

Use this sparingly—SwiftUI's layout system handles most cases more elegantly. But for custom positioning or animations, GeometryReader gives you the control you need.

Common Mistakes

The most frequent issue is expecting a stack to expand automatically. Stacks are "hugging" by default—they shrink to fit their content. If you want a stack to fill available space, you must explicitly tell it to with .frame(maxWidth: .infinity) or similar.

Another common mistake is applying frame alignment without expanding the frame first. Writing .frame(alignment: .center) without specifying a size does nothing, because the frame matches the content size and there's no extra space to align within.

Summary

When centering isn't working as expected, ask yourself: "Am I trying to align siblings relative to each other, or position something within available space?" Stack alignment handles the first case. Frame modifiers with maxWidth/maxHeight handle the second. Once that distinction clicks, SwiftUI's layout system becomes much more predictable.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.