Wrong navigation bar layout for second modal controller

Hi!


There is a bug in iOS 13 that cause the navigation bar of the second controller presented modally to have a wrong layout.


To reproduce this error present a navigation controller modally (Form Sheet). The navigation bar of this controller will be ok.

From this controller present another navigation controller modally. The toolbar of the second controller will have a wrong layout. The height is wrong and the button items are not properly aligned (see the image below).


ios13-navigation-bar-issue.png


The problem disappear after rotating the device.


To fix this issue you need to manually call the navigation bar setNeedsLayout in the viewWillAppear method of the second controller:


override func viewWillAppear(_ animated: Bool) {
     super.viewWillAppear(animated)
     if #available(iOS 13.0, *) {
          navigationController?.navigationBar.setNeedsLayout()
     }
}


Hope this helps.


Alan

Replies

It's also happening here and I was going crazy with that. Lost almost a day! Thanks for the workaround!
I filled a bug report to Apple (FB7322599).

Thank you.

Thanks!

I had been looking for a solution for the whole morning.

This solved my problem.

I can confirm this glitch is still there on iOS 13.1.2. It seems to happen only on second-level navigation controllers, i.e. a nav controller presented on top of another one. Interestingly, the third level seems to be fine. What a weird bug. And what a shame it hasn't been fixed since it was reported for beta.


The proposed workaround is good though, thank you!

Any news related to the bug you reported to Apple ??

Still happening on iOS 13.2. When trying to present a second ViewController, layout setup is being ignored, should be set again. In my case Dark Mode is not supported in the application and should be disabled manually for second NavigationController.


Your workaround is working properly! thanks!

Nothing yet. :/

Sorry,


I tried the run as DaleOne's suggestion on iOS13.2.2 as shown below. I got the same gap between navigation controller and View Controller problem. (My iOS is 13.2)


override func viewWillAppear(_ animated: Bool) {

super.viewWillAppear(animated)

print("In viewWilAppear")

if #available(iOS 13.0, *){

navigationController?.navigationBar.setNeedsLayout()

print("iOS 13.0, *")

} else {

print("else")

}

}



As the time I change replace the ? to ! as shown below.

navigationController!.navigationBar.setNeedsLayout()


I got the following error.

Unexpectedly found nil while unwrapping an Optional value: file /Users/angela_m_li/Desktop/GapInViewController/GapInViewController/ViewController.swift, line 19


It seems like it the above line will have nil result and so it will not be executed.


Is it any other suggestion to get rid of the gap?

If you have that error then it means that your controller is not contained in a navigation controller.

This fix only applies if you are modally presenting a navigation controller.

This bug still exists on iOS 13.3!

On iPad OS 13.3, the issue seems to also occur when assigning the root-view controller after creating the UINavigationController.


// This works as expected
let navigationController = UINavigationontroller(rootViewControlller: rootViewController)
present(navigationController, animated: true)

// This results in invalid layout on the navigation bar.
//
// Can be worked around by calling navigationController?.navigationBar.setNeedsLayout() in
// viewDidAppear of the root view controller. The navigation bar does however have invalid layout
// while the modal is animating in.
let navigationController = UINavigationController()
navigationController.setViewControllers([rootViewController], animated: false)
present(navigationController, animated: true)

With this bug still present the setNeedsLayout isn't working for me with Swift 4. The following is however working for me.


override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if #available(iOS 13.0, *) {
            self.view.layoutIfNeeded()
            self.view.updateConstraintsIfNeeded()
        }
    }

Still broken, just differently on iPhone iOS 13.4 golden master.

Still broken in 13.4.1😢

and it only works if put setNeetsLayout() in next main thread runLoop (https://stackoverflow.com/questions/57784596/how-to-prevent-gap-between-uinavigationbar-and-view-in-ios-13)