SwiftUI Blog

Mastering SwiftUI: Your Guide to Building Beautiful, Intuitive Apps.

Layout in SwiftUI

When we create a SwiftUI project in Xcode, we see something like this

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

Everything is centered in the middle of the screen by default. Let’s see how to move the elements to other positions.

Vertical Stack

The purpose of this stack is to organize items in a vertical flow. It’s possible to align the elements in the stack to the leading (left), trailing (right), or center (the default) positions. To add spacing between the elements, use the spacing property.

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

How can we push the objects in the VStack to the top of the view? We need to use the Spacer object.

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
            Spacer()
        }
        .padding()
    }
}

The Spacer fills all available space unless a specific size is set for it.

Horizontal Stack

The horizontal stack (HStack) is the counterpart of the vertical stack (VStack).

struct ContentView: View {
    var body: some View {
        HStack(alignment: .center, spacing: 20) {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

The possible alignments are:

  • .center
  • .top
  • .bottom
  • .firstTextBaseline
  • .lastTextBaseline

Take a look at the text baseline alignment:

struct ContentView: View {
    var body: some View {
        HStack(alignment: .lastTextBaseline, spacing: 0) {
            Color.red.frame(height: 1)
            Text("First Text Baseline").font(.title).border(.gray)
            Color.red.frame(height: 1)
        }
    }
}
struct ContentView: View {
    var body: some View {
        HStack(alignment: .firstTextBaseline, spacing: 0) {
            Color.red.frame(height: 1)
            Text("First Text Baseline").font(.title).border(.gray)
            Color.red.frame(height: 1)
        }
    }
}

As you can see, the red lines on the left and right of the text are aligned with the text’s first baseline (either the first or last line).

You can also use Spacer within an HStack to move items to the left or right as needed.

Z Stack

The ZStack is like a stack of layers, with items piled on top of each other.

struct ContentView: View {
    var body: some View {
        ZStack() {
            Text("I'm level 0")
                .foregroundStyle(Color.white)
                .padding(100)
                .background(Color.gray)
            Text("I'm level 1")
                .foregroundStyle(Color.blue)
        }
    }
}

In this case the text are overlapped:

The item on the background is the first in the ZStack and so on.

In this way the text is not readable, so we can use the .topLeading aligment to move the second on the top left corner:

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            Text("I'm level 0")
                .foregroundStyle(Color.white)
                .padding(100)
                .background(Color.gray)
            Text("I'm level 1")
                .foregroundStyle(Color.blue)
        }
    }
}

There are fifteen alignments, so try the others.

If you don’t want to use alignment, you can use the offset instead

struct ContentView: View {
    var body: some View {
        ZStack {
            Text("I'm level 0")
                .foregroundStyle(Color.white)
                .padding(100)
                .background(Color.gray)
            Text("I'm level 1")
                .foregroundStyle(Color.blue)
                .offset(x: 0, y: 80)
        }
    }
}

The X and Y coordinates are relative to the starting position of the first element.

Stacks are powerful elements in SwiftUI.