swiftuivstack

VStack with ignoresSafeArea modifier is not centered in ContentView


I have a layout question for using VStack with ignoresSafeArea modifier.

This is my code:

struct ContentView: View {
    var body: some View {
        VStack{
            Color.green
                .frame(width: 300,height: 759)
        }
        .border(Color.blue,width: 2)
        .ignoresSafeArea()
    }
}

I used iPhone 14 Pro(iOS 16.4) to debug. The default height of safe area is (852 -59 -34) = 759. Everything seems to be fine when the height of green view is smaller than 759.But when the height >= 759, the VStack is no longer centered in ContentView. This is the screen shot when the height of green view is 758:

height=758

This is the screen shot when the height of green view is 759:

enter image description here

Why the VStack is top aligned when its height is bigger than the height of default safe area ?

Thanks!


Solution

  • It doesn't align to the center in either case, it's just when you don't have ignoresSafeArea the green frame aligns to top of the safe area, and with ignoresSafeArea, it's top of the screen. This is visible on your own screenshot: if top screenshot had content aligned to the middle, it would look like this:

    enter image description here

    but instead on your screenshot, the gap from the top is larger than the gap from the bottom, and is proportionate to safe area.

    Now you say that "Everything seems to be fine when the height of green view is smaller than 759", but truth is the difference between bottom and top safe area is so small, that most of the time you won't notice that the content is slightly further from top than from the bottom. But it is. For example if you set your VStack to 300px, you will get 290px from the top, and 265 from the bottom (exactly the difference 59 -34.

    So if you really want to align your content to the middle, have a container that extends to the whole screen, including safe area, and then place your other content into it:

                ZStack {
                    VStack { 
                        Color.green
                            .frame(width: 300, height: 759)
                    }
                    .border(Color.blue, width: 2)
                }
                .ignoresSafeArea() // <-- extend to the whole screen
                .frame(maxHeight: .infinity) // <-- maximize the height