iosswiftswiftuibackground-colortabview

Background in screens in TabView w/ PageTabViewStyle doesn't fill entire vertical space available


I want a TabView that uses a PageTabViewStyle with each individual screen having a different background colour that fills the entire vertical space available (i.e. extended into the safe areas).

TabView(selection: $selection) {
    VStack {
        Text("screen 1")
    }.frame(maxWidth: .infinity, maxHeight: .infinity)
     .background(Color.green)
    
    VStack {
        Text("screen 2")
    }.frame(maxWidth: .infinity, maxHeight: .infinity)
     .background(Color.red)

}.edgesIgnoringSafeArea(.all)
 .frame(maxWidth: .infinity, maxHeight: .infinity)
 .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))

However, it looks like this:

enter image description here

And after I scroll to the bottom:

enter image description here

The white colour can be changed if I set a background colour for the TabView itself, which would be fine if each screen used the same background colour. Is there any way for individual screens within the TabView to have a unique background colour set that fills the entire screen?


Solution

  • Normally I wouldn't suggest GeometryReader, but this doesn't look like intended behavior on Apple's part. The key is expanding the background modifier color to a large enough height so that you can't see the white background behind the tab.

    Thank you, Asperi, for sharing the link to a similar question for inspiration:

    https://stackoverflow.com/a/62596307/12299030

    struct ContentView: View {
        
        @State private var selection: Int = 0
        
        var body: some View {
            GeometryReader { geo in
                TabView(selection: $selection) {
                    
                    VStack {
                        Text("Screen 1")
                    }.frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(
                        EmptyView()
                            .frame(minHeight: 2 * geo.size.height)
                            .background(Color.green)
                    )
                    .tag(0)
                    
                    VStack {
                        Text("Screen 2")
                    }.frame(maxWidth: .infinity, maxHeight: .infinity)
                    .background(
                        EmptyView()
                            .frame(minHeight: 2 * geo.size.height)
                            .background(Color.red)
                    )
                    .tag(1)
    
                }.edgesIgnoringSafeArea(.all)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            }
        
        }
        
    }
    

    Using an EmptyView combined with a set minimum height of 2 times the current height ensures that the user can scroll up and down, reaching the bounce-back distance, and not see a white background. Put any background you'd like on this view.

    You may be able to swap out EmptyView with whatever you'd like, but that was the first thing that came to mind. I added .tag() and selection so that ContentView can be ran on its own in case you'd like to experiment.