Paul Peelen
Paul Peelen

Reputation: 10329

UINavigationController showing space for statusbar on push

When I push, using storyboard segue, to the next view, it loads a space for the statusbar, even though the next view has set the prefersStatusBarHidden to false.

I have also tried by subclassing the UINavigationController and setting prefersStatusBarHidden to false in there, but still the view loads a space for it. Also automaticallyAdjustsScrollViewInsets is set to false.

Push to view

The view that is loaded consist of an UIViewController which has a UITableView. The background color of the UIViewController is (for testing) set to orange and the one for the table view is set to Pink. Neither of these colours are shown.

After som testing, it seems to me that the UINavigationController adds a space for its root view and removes that space after animating the push. If I set the background color of the UINavigationController to purple, I get the following result:

Result 2

This shows that the view it is pushing to is neither renedered nor in the correct Y position. I can't seem to find why this is.

My UINavigationController is contained in an UIViewController which has a container for the view (rootViewController). The navigation controller is create programatically whenever a root-page is requested to be loaded. This is that code:

/// Load a view controller with UINavigationController into the 
/// rootViewController and display it
///
/// - Parameter viewController: The view controller to show
func loadViewControllerPage(_ viewController: UIViewController) {
    let nav = UINavigationController(rootViewController: viewController)

    // No bar, please
    nav.isNavigationBarHidden = true

    // Make the view get in there propperly
    nav.willMove(toParentViewController: self)
    addChildViewController(nav)
    nav.view.willMove(toSuperview: rootViewController)
    nav.view.frame = rootViewController.bounds
    rootViewController.addSubview(nav.view)
    nav.view.didMoveToSuperview()
    nav.didMove(toParentViewController: self)
    rootViewController.bringSubview(toFront: nav.view)

    /* Test if this fixes the statusbar issue
    nav.edgesForExtendedLayout = .all
    nav.automaticallyAdjustsScrollViewInsets = false
    nav.extendedLayoutIncludesOpaqueBars = false
    */

    currentNav = nav

    // Cleanup
    for child in childViewControllers {
        if let c = child as? UINavigationController, c != nav && c.view.isDescendant(of: rootViewController) && c != menuView {
            c.removeFromParentViewController()
            c.view.removeFromSuperview()
        }
    }
}

Any suggestions on how I can solve this?

Upvotes: 2

Views: 1530

Answers (1)

SwiftArchitect
SwiftArchitect

Reputation: 48514

Synopsis

  • Do not attempt to trigger iOS messages. Invoking didMoveToSuperview() programmatically is a sure sign that the design is likely flawed, or unnecessarily convoluted at best
  • No need to use loadViewControllerPage to push views onto a navigation controller or replace the root view controller
  • No need to programmatically create navigation controllers. Let Interface Builder prepare the resource for you, and load it on demand if you must.
  • The whole point of a navigation controller is to handle navigation ; do not bypass that mechanism and load views by hand

Notice how the status bar, visible on the orange view, isn't on the blue one. See animation.

Animation showing the status bar disappearing


Suggestions

When I push, using storyboard segue, to the next view, it loads a space for the statusbar, even though the next view has set the prefersStatusBarHidden to false.

Hiding Status Bar

To hide the status bar in your second view controller, set prefersStatusBarHidden to true, not false.

override var prefersStatusBarHidden:Bool {
    return true
}

Hiding Navigation Bar

If you do not want to display the navigation bar, change the Bar Visibility in the Navigation Controller Attributes Inspector.

Using storyboard segue

No code required for this. If you positively must use segues programmatically, see this StackOverflow answer.

Programmatically creating a Navigation Controller

No need to go through this path. Use a Storyboard ID to find and load the navigation controller from the storyboard.

UINavigationController subclass

Why so much code around loadViewControllerPage, and why subclassing UINavigationController?

Controlling custom transitions

If the object of your custom UIViewController loading is the animation, see this StackOverflow post.

Design transitions in the storyboard

Navigation Controller visibility, status bar visibility, segues, all defined by resources and yielding very little to no code.

enter image description here

Upvotes: 3

Related Questions