Home > Software design >  SwiftUI ZStack alignment works strangely
SwiftUI ZStack alignment works strangely

Time:03-11

I created very simple views with SwiftUI including ZStack.

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            Text("aaa")
                .frame(width: 50, height: 50)
                .font(.system(size: 20))
        }
        .frame(width: 142.0, height: 142.0)
        .background(.pink)
    }
}

I expected that the Text("aaa") would appear in the top leading of pink square.

But the result was this.

ZStack without Color.clear

More strangely, it works well if I add 'Color.clear' to ZStack like this.

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            Color.clear
            Text("aaa")
                .frame(width: 50, height: 50)
                .font(.system(size: 20))
        }
        .frame(width: 142.0, height: 142.0)
        .background(.pink)
    }
}

And the result it this.

ZStack with Color.clear

I cannot understand this situation. SwiftUI is totally crazy.

Does anybody know about this?

CodePudding user response:

The elements of the ZStack are laid out and aligned based on the size of the largest child, not the frame of the ZStack itself. You should think of the "content area" of the stack being seperate to the frame of the stack.

When you add a Color.clear, its default frame is unbounded (the height and width are infinity), so when it is added to the ZStack, it will grow the "content area" to the maximum possible size. This makes the content area of the stack the same size as the ZStacks frame.

You can achieve the same result (in a clearer way) by using a Spacer() with explicit infinite bounds. This will ensure the children always fill the same available to them.

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            Spacer()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            Text("aaa")
                .frame(width: 50, height: 50)
                .font(.system(size: 20))
        }
        .frame(width: 142.0, height: 142.0)
        .background(.pink)
    }
}
  • Related