WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

Using stacks to arrange views

Paul Hudson    @twostraws   

When we return some View for our body, SwiftUI expects to receive back some kind of view that can be displayed on the screen. That might be a navigation view, a form, a text view, a picker, or something else entirely, but it must conform to the View protocol so that it can be drawn on the screen.

If we want to return multiple things neatly arranged then we have various options, but three are particularly useful. They are HStack, VStack, and ZStack, which handle horizontal, vertical, and, er, zepth.

Let’s try it out now. Our default template looks like this:

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

That has a VStack in there already, which means the image appears above the text. However, we could make it simpler, like this:

var body: some View {
    Text("Hello, world!")
    Text("This is another text view")
}

We haven't said it's a VStack, but SwiftUI is figuring it out for us. So, we can choose to place the two text views loosely like that, or in an explicit VStack:

var body: some View {
    VStack {
        Text("Hello, world!")
        Text("This is inside a stack")
    }
}

Yes, the result is the same is here, but there are three important differences:

  1. Being explicit allows us to specify how much space to place between the views.
  2. It also allows us to specify an alignment – whether the view should be placed on the left, right, or center of each other.
  3. If we don't explicitly ask for a vertical stack, SwiftUI is free to arrange those views in a different way – if they were inside a larger view that used horizontal placement, they might also appear horizontally.

By default VStack places some automatic amount of spacing between the two views, but we can control the spacing by providing a parameter when we create the stack, like this:

VStack(spacing: 20) {
    Text("Hello, world!")
    Text("This is inside a stack")
}

By default, VStack aligns its views so they are centered, but you can control that with its alignment property. For example, this aligns the text views to their leading edge, which in a left-to-right language such as English will cause them to be aligned to the left:

VStack(alignment: .leading) {
    Text("Hello, world!")
    Text("This is inside a stack")
}

Alongside VStack we have HStack for arranging things horizontally. This has the same syntax as VStack, including the ability to add spacing and alignment:

HStack(spacing: 20) {
    Text("Hello, world!")
    Text("This is inside a stack")
}

Vertical and horizontal stacks automatically fit their content, and prefer to align themselves to the center of the available space. If you want to change that you can use one or more Spacer views to push the contents of your stack to one side. These automatically take up all remaining space, so if you add one at the end a VStack it will push all your views to the top of the screen:

VStack {
    Text("First")
    Text("Second")
    Text("Third")
    Spacer()
}

If you add more than one spacer they will divide the available space between them. So, for example we could have one third of the space at the top and two thirds at the bottom, like this:

VStack {
    Spacer()
    Text("First")
    Text("Second")
    Text("Third")
    Spacer()
    Spacer()
}

We also have ZStack for arranging things by depth – it makes views that overlap. In the case of our two text views, this will make things rather hard to read:

ZStack {
    Text("Hello, world!")
    Text("This is inside a stack")
}

ZStack doesn’t have the concept of spacing because the views overlap, but it does have alignment. So, if you have one large thing and one small thing inside your ZStack, you can make both views align to the top like this: ZStack(alignment: .top) {.

ZStack draws its contents from top to bottom, back to front. This means if you have an image then some text ZStack will draw them in that order, placing the text on top of the image.

Try placing several horizontal stacks inside a single vertical stack – can you make a 3x3 grid?

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.8/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.