SwiftUI Navigation and status bar clash in color/transparency when inside TabView

Viewed 3155

My app consists of a few views across a few different tabs inside a TabView. These views create their own NavigationViews. Unfortunately the existence of the TabView is causing their colors and transparency to clash with the app's status bar, which is no longer in line with the navigation bar.

This is easily reproduced in a sample app using the following code.

struct ContentView: View {
    var body: some View {
        TabView {
            NavView()
        }
    }
}

struct NavView: View {
    var body: some View {
        NavigationView {
            List {
                ForEach(0..<10, id: \.self) { _ in
                    Section(header: Text("Foo")) {
                        Text("Bar")
                    }
                }
            }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("Foobar")
        }
    }
}

I'm using the grouped list style to make the styling changes more apparent, but it's the same with the default style.

Is there a SwiftUI API to access the status bar styling? Or possibly some other workaround?

large navigation bar screenshot

inline navigation bar screenshot

2 Answers

As per Apple's documentation, edgesIgnoringSafeArea(_:) should be applied to TabView:

https://developer.apple.com/documentation/swiftui/vsplitview/3288813-edgesignoringsafearea

Extends the view out of the safe area on the specified edges.

struct ContentView: View {
    var body: some View {
        TabView {
            NavView()
        } // .edgesIgnoringSafeArea(.top) no longer necessary as of iOS 13.4
    }
}

NOTE: It appears Apple changed the default behavior and this is no longer necessary with iOS 13.4.

For some reason, it stopped working properly for me. The situation was it was working without edgesIgnoringSafeArea(_:) applied just for the simulator but not a device. And vice versa when it is applied to it.

Created a little modifier to fix it.

struct EdgeIgnoringSafeAreaModifier: ViewModifier {

    var edges: Edge.Set

    func body(content: Content) -> some View {
        #if targetEnvironment(simulator)
        return content
        #else
        return content.edgesIgnoringSafeArea(self.edges)
        #endif
    }
}

extension View {
    func edgeIgnoringSafeAreaForDevice(_ edges: Edge.Set) -> some View {
        self.modifier(EdgeIgnoringSafeAreaModifier(edges: edges))
    }
}
Related