SwiftUI: Hiding the status bar with TabView and nested NavigationView's

Using XCode 12 Beta and iOS 14, I'm unable to hide the status bar when a NavigationView is nested inside a TabView. Consider:

Code Block
     TabView(selection: $selection) {
       NavigationView {
        ViewOne()
        .navigationBarTitle("View One")
      }
      .tabItem {
        Label("View One", systemImage: "doc.plaintext")
      }
      .tag(TabItem.viewOne)
      .statusBar(hidden: true)
    }

The above code only hides the status bar if you remove the parent TabView. I also tried to hide the status bar onAppear:

Code Block
     TabView(selection: $selection) {
       NavigationView {
        ViewOne()
        .navigationBarTitle("View One")
        .onAppear {
          isStatusBarHidden = true
        }
        .onDisappear {
          isStatusBarHidden = false
        }
      }
      .tabItem {
        Label("View One", systemImage: "doc.plaintext")
      }
      .tag(TabItem.viewOne)
      .statusBar(hidden: isStatusBarHidden)
    }

This also doesn't work. I've also tried hiding the status bar directly on the TabView. Any suggestions?

Replies

Have the "same" issue:

Code Block swift
import SwiftUI
struct PXStartupView: View {
    @State var ready = false
    var body: some View {
        NavigationView{
            ZStack{
                Color.white
                Image("Icon-Startup")
                NavigationLink(destination: PXMainView(), isActive: self.$ready){
                    EmptyView()
                }
            }
            .navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)
            .navigationBarTitle("", displayMode: .inline)
            .edgesIgnoringSafeArea(.all)
        }
        .navigationBarHidden(true)
        .navigationBarBackButtonHidden(true)
        .navigationBarTitle("", displayMode: .inline)
        .navigationViewStyle(StackNavigationViewStyle())
        .statusBar(hidden: true)
    }
}

Works fine on iOS 13 (not status bar), but show status bar on iPad iOS 14
Hopefully this helps someone diagnose - tested via Xcode 12.0 beta 2 and iOS 14.0 public beta:

SwiftUI views NOT wrapped in NavigationView hide the status bar correctly via ".statusBar(hidden: true)" modifier.
SwiftUI views wrapped in NavigationView do not process the status bar correctly via ".statusBar(hidden: true)" modifier.
Not seeing much of a difference yet regarding portrait vs landscape.

Worked correctly at least through 13.5 but current 13.x.

Cheers.
Same here — .statusBar(hidden: true) doesn't work if view is wrapped in NavigationView on iOS 14.
Has anyone raised this with apple?
I'm having the same issue...statusBar cannot be hidden on any level if the view has a NavigationView...

Has anyone come up with a solution?

XCode 12, iOS 14
Man, I just wish Apple would spend some time cleaning up those SwiftUI bugs. It's crazy how many bugs apple just leaves there!

I faced the same issue, but was able to solve it by adding more keys to the info.plist file (Xcode 12 and iOS14).

As stated in this thread (https://stackoverflow.com/questions/56896719/how-to-hide-the-status-bar-in-swiftui) you just have to paste

<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>

in your info.plist file.

Afterwards


.edgesIgnoringSafeArea(.all)
.statusBar(hidden: true)

worked just fine for me.

The issue is finally solved with Xcode 13.0 beta 3 - you can attach the statusBarHidden modifier to both a TabView and a NavigationView and the status bar hides as expected.

I found the only way to get this to work per view is to wrap your rootView in a HostingController like:

class HostingController<ContentView>: UIHostingController<ContentView> where ContentView : View {

    

    init(view: ContentView) {

        super.init(rootView: view)



        NotificationCenter.default.addObserver(forName: .onDarkStatusBar, object: nil, queue: .main) { _ in

            self.statusBarEnterDarkBackground()

        }

        

        NotificationCenter.default.addObserver(forName: .onLightStatusBar, object: nil, queue: .main) { _ in

            self.statusBarEnterLightBackground()

        }

        

        NotificationCenter.default.addObserver(forName: .onShowStatusBar, object: nil, queue: .main) { _ in

            self.statusBarShow()

        }

        

        NotificationCenter.default.addObserver(forName: .onHideStatusBar, object: nil, queue: .main) { _ in

            self.statusBarHide()

        }

    }

    

    @objc required dynamic init?(coder aDecoder: NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }

    

    private var isDarkContentBackground = false

    private var isStatusBarHiden = false



    func statusBarEnterDarkBackground() {

        isDarkContentBackground = false

        setNeedsStatusBarAppearanceUpdate()

    }



    func statusBarEnterLightBackground() {

        isDarkContentBackground = true

        setNeedsStatusBarAppearanceUpdate()

    }

    

    func statusBarHide() {

        isStatusBarHiden = true

        setNeedsStatusBarAppearanceUpdate()

    }



    func statusBarShow() {

        isStatusBarHiden = false

        setNeedsStatusBarAppearanceUpdate()

    }



    override var preferredStatusBarStyle: UIStatusBarStyle {

        if isDarkContentBackground {

            return .lightContent

        }

        else

        {

            return .darkContent

        }

    }

    

    override var prefersStatusBarHidden: Bool {

      return isStatusBarHiden

    }



}

Use as

let window = UIWindow(windowScene: windowScene)

            window.rootViewController = HostingController(view: contentView)

Then send out a notification from onDissapear and onAppear.

extension Notification.Name {

   static let onDarkStatusBar = Notification.Name("onDarkStatusBar")

    static let onLightStatusBar = Notification.Name("onLightStatusBar")

    static let onHideStatusBar = Notification.Name("onHideStatusBar")

    static let onShowStatusBar = Notification.Name("onShowStatusBar")

}

Using

                            .onAppear {

                                NotificationCenter.default.post(name: Notification.Name.onHideStatusBar, object: nil)

                            }

                            .onDisappear {

                                NotificationCenter.default.post(name: Notification.Name.onShowStatusBar, object: nil)

                            }