The SwiftUI Field Guidebeta

Overlay

Overlay is a simple yet powerful modifier that overlays a view on another view. For example, here's a text view with a blue overlay:

Code
Text("Hello, world. This is a longer text.")    .overlay {        Color.blue            .opacity(0.2)    }
Preview
200

In the example above, the blue color matches the bounding box of the text exactly. This is no coincidence. During layout, the overlay takes the reported size of the text and proposes it to its secondary child (the blue color):

Preview
Tree

 

1/1
200

In general, when you want the size of the overlaid view to be dependent on the size of the primary view, you should use the overlay modifier. This is because the overlay modifier proposes the size of the primary view to the secondary view. When you want the sizes of these two views to be independent, you should consider using a ZStack instead.

The reported size of the overlay is the size of the primary child. While we don't see the difference in an isolated example, it becomes more important when the view is surrounded by other views. For example, we can overlay a view with negative padding around an existing view without influencing the layout:

Code
HStack {    Text("One")    Text("Two")        .overlay {            if highlighted {                RoundedRectangle(cornerRadius: 5)                    .foregroundStyle(Color.purple)                    .opacity(0.5)                    .padding(
)
} } Text("Three")}
Preview

Overlay also provides an alignment parameter, and the default is .center. This works as expected:

Code
Color.purple    .frame(width: 100, height: 100)    .overlay {        Text("Hi")    }
Preview
leadingcentertrailing
topcenterbottom

One of the most useful parts of overlay is that it proposes the size of its primary child to its secondary child. However, there are cases where we might not want this behavior. In the example below, we have a badge view similar to the one on the alignment page. When we apply it on a large enough view, it renders fine. However, when the primary child is small, the badge gets proposed a small size as well and can truncate the text. To decouple the sizes, we can apply the fixedSize modifier to the badge view.

Code
BuyButton()    .overlay(alignment: .topTrailing) {        MyBadge()            /* .fixedSize() */            .alignmentGuide(.top) { dim in                dim.height / 2            }            .alignmentGuide(.trailing) { dim in                dim.width / 2            }    }
Preview
ButtonText

On the ZStack page we can look at a similar example of a badge view, but built with a ZStack.