Search code examples
iosuinavigationcontrollerswiftuiuinavigationbaruihostingcontroller

Hide UINavigationController's navigationBar when the root controller is a UIHostingController


I am struggling to hide the navigationBar, which would properly be hidden if the root controller wasn't a SwiftUI UIHostingController.

I tried the following:

  • Setting navigationController.isNavigationBarHidden = true after creating it, at viewDidLoad and viewWillAppear.

  • Adding both .navigationBarHidden(true) and .navigationBarBackButtonHidden(true) for the UIHostingController's rootView.

Could it be an Apple bug? I am using Xcode 11.6.

All my attempts together:

class LoginController: UINavigationController, ObservableObject
{
    static var newAccount: LoginController
    {
        let controller = LoginController()
        let view = LoginViewStep1()
            .navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)
        controller.viewControllers = [UIHostingController(rootView: view)]
        controller.isNavigationBarHidden = true
        return controller
    }
    
    override func viewWillAppear(_ animated: Bool)
    {
        super.viewWillAppear(animated)
        
        self.isNavigationBarHidden = true
    }

    override func viewDidLoad()
    {
        super.viewDidLoad()

        self.isNavigationBarHidden = true
    }
}

struct LoginViewStep1: View
{
    // ...
    
    var body: some View
    {
        VStack {
            // ...
        }
        .navigationBarHidden(true)
        .navigationBarBackButtonHidden(true)
    }
}

Solution

  • Here is a solution. Tested with Xcode 11.4 / iOS 13.4

    demo

    Modified your code:

    class LoginController: UINavigationController, ObservableObject
    {
        static var newAccount: LoginController
        {
            let controller = LoginController()
            let view = LoginViewStep1()
            controller.viewControllers = [UIHostingController(rootView: view)]
    
            // make it delayed, so view hierarchy become constructed !!!
            DispatchQueue.main.async {
                controller.isNavigationBarHidden = true
            }
    
            return controller
        }
    }
    
    struct LoginViewStep1: View
    {
        var body: some View
        {
            VStack {
                Text("Hello World!")
            }
        }
    }
    

    tested part in SceneDelegate

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
    
        window.rootViewController = LoginController.newAccount
    
        self.window = window
        window.makeKeyAndVisible()
    }