0

I'm curious, does anyone understand what .position(x:y:) is doing to the layout process for a containing ZStack? I've looked at Apple's documentation on "Making fine adjustments to a view’s position" and it doesn't mention anything about this.

See the following example for an illustration:

struct PositionTest: View {
    var body: some View {
        VStack {    // This VStack is just a small container to have small screenshots
            ZStack {
                Color(.yellow)
                    .frame(width: 60, height: 40)
                Color(.red)
                    .frame(width: 3, height: 3)
//                    .position(x: 5, y: 5)   // Line A
            }
//            .frame(width:60, height: 40)    // Line B
            .border(.green)
        }
        .frame(width: 70, height: 70)
        .overlay(Rectangle().stroke(.black, style: StrokeStyle(lineWidth: 1, dash: [1, 2]))) // dashed border
    }
}

Before applying the .position, it all looks as you'd expect (the red square has been added at the centre of the stack of views):

No Position

When I apply .position by uncommenting "Line A" in the sample code, which I expect to simply position the red square at (5, 5) relative to the top-left corner of the yellow rectangle, I get this:

Position Only

To get the result I expect (and this is what is being done in Apple's example above, without explanation), I have to limit the size of the ZStack to the size of it's largest child by uncommenting "Line B". This is what it looks like:

Position and Frame

So the question is, why does adding .position to the yellow Rectangle, change the size of the containing ZStack (with the green border)? Can anyone point us to some descriptions of the SwiftUI Layout procedure that include this detail?

Curious Jorge
  • 354
  • 1
  • 9

1 Answers1

0

The documentation to position(x:y:) states that it positions the center of the view at the specified coordinates "in its parent’s coordinate space". However, it seems that the parent in question is not the ZStack, but the first parent with a fixed size, which is the VStack in your case. I find this surprising too.

In other words, as soon as a view inside the ZStack has absolute positioning, the ZStack automatically becomes greedy and uses all of the space available. It's as if you had applied .frame(maxWidth: .infinity, maxHeight: .infinity) to the ZStack at the same time.

Another way to get the result you are expecting is therefore to reduce the size of the containing VStack to 60x40.

Benzy Neez
  • 1,546
  • 2
  • 3
  • 10