Rotating iPhone to landscape mode causes previously hidden navigation bar of detail view to appear but navigation bar of sidebar to remain hidden

My app has a split view with a root view and a detail view, both of which are inside their own navigation view controller. The navigation bar of the detail view can be hidden to allow the user to stay more focused on the content.

The problem is that when the navigation bar of the content view is hidden in portrait mode and the iPhone is rotated to landscape mode, the navigation bar of the content view becomes visible automatically and the sidebar appears on the left side, but the navigation bar of the sidebar is hidden.

Is it expected that the navigation bar becomes visible automatically when rotating the device? Why is the navigation bar of the sidebar hidden? Is this related to hiding the navigation bar of the content view and why does this happen? What am I supposed to do so that the navigation bar of the sidebar remains visible at all times?

For comparison the two cases:

  1. After rotation when navigation bar of content view was visible:

  1. After rotation when navigation bar of content view was hidden:

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        window = UIWindow(windowScene: scene as! UIWindowScene)
        window!.rootViewController = SplitViewController()
        window!.makeKeyAndVisible()
    }
    
}

class SplitViewController: UISplitViewController, UISplitViewControllerDelegate {

    var detailNavigationViewController: UINavigationController!
    
    init() {
        super.init(nibName: nil, bundle: nil)
        detailNavigationViewController = UINavigationController(rootViewController: DetailViewController())
        viewControllers = [UINavigationController(rootViewController: RootViewController())]
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func showDetail() {
        showDetailViewController(detailNavigationViewController, sender: nil)
    }

}

class RootViewController: UIViewController {
    
    override func loadView() {
        navigationItem.title = "Root"
        navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .add)
        let button = UIButton(primaryAction: UIAction(handler: { [self] _ in
            (splitViewController as! SplitViewController).showDetail()
        }))
        button.setTitle("Show detail", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        view = UIView()
        view.layer.backgroundColor = UIColor(white: 0.9, alpha: 1).cgColor
        view.addSubview(button)
        NSLayoutConstraint.activate([NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0), NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)])
    }
    
}

class DetailViewController: UIViewController {
    
    override func loadView() {
        navigationItem.title = "Detail"
        navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "sidebar.leading"), primaryAction: UIAction(handler: { _ in
            UIView.animate(withDuration: 0.3) { [self] in
                self.splitViewController!.preferredDisplayMode = .oneOverSecondary
            }
        }))
        navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .add)
        let button = UIButton(primaryAction: UIAction(handler: { [self] _ in
            navigationController!.setNavigationBarHidden(!navigationController!.isNavigationBarHidden, animated: true)
        }))
        button.setTitle("Toggle navigation bar", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        view = UIView()
        view.addSubview(button)
        NSLayoutConstraint.activate([NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0), NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0)])
    }

}

I created FB24413608.

Answered by DTS Engineer in 902221022

Hello @Nickkk,

Thank you for filing and providing your sample project. I shared your report with the relevant engineering team and they are aware of the issue.

Is it expected that the navigation bar becomes visible automatically when rotating the device?

No, it seems this behavior should only reproduce on larger devices where there is still a Split View Controller sidebar.

Updates will be provided to you through Feedback Assistant. Use this thread to communicate updates you find as you test new releases.

For more details on Feedback Status, please see “Understanding the Status of Your Feedback” linked here: https://developer.apple.com/bug-reporting/status

What am I supposed to do so that the navigation bar of the sidebar remains visible at all times?

They did not provide an explicit workaround with me directly, however you can try to explicitly re-assert the primary column's navigation bar visibility after each transition completes:

override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil) { [weak self] _ in
        guard let self, let primaryNav = self.viewControllers.first as? UINavigationController else { return }
        primaryNav.setNavigationBarHidden(false, animated: false)
    }
}

Place this override in your UISplitViewController subclass.

I hope this information is helpful.

 Travis

Hello @Nickkk,

Thank you for filing and providing your sample project. I shared your report with the relevant engineering team and they are aware of the issue.

Is it expected that the navigation bar becomes visible automatically when rotating the device?

No, it seems this behavior should only reproduce on larger devices where there is still a Split View Controller sidebar.

Updates will be provided to you through Feedback Assistant. Use this thread to communicate updates you find as you test new releases.

For more details on Feedback Status, please see “Understanding the Status of Your Feedback” linked here: https://developer.apple.com/bug-reporting/status

What am I supposed to do so that the navigation bar of the sidebar remains visible at all times?

They did not provide an explicit workaround with me directly, however you can try to explicitly re-assert the primary column's navigation bar visibility after each transition completes:

override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil) { [weak self] _ in
        guard let self, let primaryNav = self.viewControllers.first as? UINavigationController else { return }
        primaryNav.setNavigationBarHidden(false, animated: false)
    }
}

Place this override in your UISplitViewController subclass.

I hope this information is helpful.

 Travis

this behavior should only reproduce on larger devices where there is still a Split View Controller sidebar

Thanks, so do you mean on iPads? But if the navigation bar of the sidebar disappears on iPads, that would still be a problem. Why would it be expected on iPad but not on iPhone?

Rotating iPhone to landscape mode causes previously hidden navigation bar of detail view to appear but navigation bar of sidebar to remain hidden
 
 
Q