0

I have a UINavigationController which contains two UIViewControllers, set up in a storyboard:

enter image description here

Each of these controllers has a UISearchBar included in their navigation item by the following line in viewDidLoad():

navigationItem.searchController = UISearchController(searchResultsController: nil)

When the second view controller is pushed onto the navigation stack while the search bar is visible in the first view, the animation does not render correctly: the navigation height does not transition to the correct height smoothly - it transitions to the size of the next navigation item if it had its search bar visible, and then snaps to the correct size when the animation is complete. This results in part of the view being obscured during the animation.

See the attached recording, showing both the "normal" animation (when the search bar is hidden) and then the incorrect animation:

I've also created put together a very simple reproduction of this issue, with just 7 lines of code in its view controller, which demonstrates the issue.

Is there a way I can prevent this happening?

Andrew Bennet
  • 2,600
  • 1
  • 21
  • 55
  • It looks like the navigation height is taking into account the frames for the search bar. We're going to need to see code of how you're transitioning / creating the navigation bar height to debug more thoroughly. – Mocha Mar 05 '19 at 20:47
  • I'm not actually transitioning the height myself at all. The segues are defined in the storyboard, and the only adjustment I've made to the navigation item is to assign to the `navigationItem.searchController` property. I've added a screenshot and also a simple reproduction repository. – Andrew Bennet Mar 05 '19 at 22:21

1 Answers1

0

-- Update --

Link to a Very similar problem.. Broken UISearchBar animation embedded in NavigationItem

It seems the UINavigationController is buggy. Moving the func to viewDidAppear prevents the initial push's bug. However, it causes an NSException..

Only one palette with a top boundary edge can be active outside of a transition.

It can be alleviated by setting the searchController in the main thread.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if navigationItem.searchController == nil { // To prevent search bar from being lost on pop
        DispatchQueue.main.async {
            self.navigationItem.searchController = UISearchController(searchResultsController: nil)
        }
    }
}
Mocha
  • 2,035
  • 12
  • 29
  • This doesn't seems to prevent the issue on the very first push segue. Subsequent push and pops are OK though. However, this isn't a viable solution for me as it will result in any search state (e.g. whether a search is active, what the text in the search bar is) being lost when navigating back to the first view. I also tried: `if navigationItem.searchController == nil { navigationItem.searchController = UISearchController(searchResultsController: nil) }`, but this doesn't solve the problem at all. – Andrew Bennet Mar 06 '19 at 08:07
  • Updated answer to solve your issues. – Mocha Mar 06 '19 at 17:10
  • This does work well normally, but when the search bar is active, it seems that the view controller which gets pushed onto the navigation stack is missing a navigation item altogether! You are quite right that this is a duplicate question, thanks for letting me know. – Andrew Bennet Mar 07 '19 at 11:31
  • I've come across another approach - I have [left an answer](https://stackoverflow.com/a/55043782/5513562) on the original question and have voted to close this one. Thanks for your help. – Andrew Bennet Mar 07 '19 at 12:27