The SwiftUI Field Guidebeta

ZStack

A ZStack is a container that layers its views on top of each other. Unlike an overlay or background, the views in a ZStack have sizes that are independent of each other. The first child of the ZStack is at the bottom, and the last view is at the top. The ZStack takes its proposed size and proposes that same size to each of its children. Once all children have their sizes, they are aligned. Here's a simple example:

Code
ZStack {    Color.yellow    Circle()        .fill(Color.orange)    Text("Hello")        .foregroundStyle(.black)}
Preview
leadingcentertrailing
topcenterbottom

The reported size of the ZStack is the union of all the frames of the children. In most cases, this means that the ZStack will be as large as the largest child. However, the following example shows how the ZStack combines the frames of both views:

Code
ZStack {    Color.yellow        .frame(width: 50)    Color.orange        .frame(height: 50)}.border(Color.red).padding()
Preview
300

ZStack vs. Overlay

It's not always clear when to use a ZStack and when to use an overlay (or background). The main difference is that the sizes of the views in a ZStack are independent of each other, while the sizes of the views in an overlay are not. With an overlay, the overlaid view is proposed the size of the primary view. In general, when we want the size of a view to be dependent on the size of another view, we'd use an overlay or background, whereas if they are independent, we use a ZStack. Likewise, when we want to display one view on top of another view without modifying the size of the underlying view, we'd use an overlay.

The example below is similar to the the badge example from the overlay page. However, here we can switch between using a ZStack and an overlay. When we add the badge using a ZStack, the size of the button grows, and the buttons aren't aligned. However, when we use an overlay, the reported size of the button stays the same, and the buttons are aligned.

Code
HStack {    CartButton()        .overlay(alignment: .topTrailing) {            Badge()                .alignmentGuide(.top) { dim in                    dim.height / 2                }                .alignmentGuide(                    .trailing                ) { dim in dim.width / 2 }        }        /* .border(Color.pink) */    CartButton()        /* .border(Color.pink) */}
Preview
ZStackOverlay

In the following example, we use an overlay to display a highlight effect. When we switch to a ZStack, the size of the highlight is not dependent on the size of the text anymore. Instead, the ZStack will grow as large as the rounded rectangle. Because the rounded rectangle is completely flexible, it will take up all the remaining space.

Code
HStack {    Text("One")    Text("Two")        .overlay {            RoundedRectangle(cornerRadius: 8)                .fill(Color.purple)                .opacity(0.5)                .padding(-8)        }    Text("Three")}
Preview
ZStackOverlay

Alignment Guides

By using alignment guides with a ZStack, we can create container views that grow to the union of the bounds of the children. Before the Layout protocol was available, we used this technique to build container views. For example, in this Swift Talk Episode, we can see how to build a flow layout using ZStacks and custom alignment guides.