By default in iOS 15, navigation bars are transparent when scrolled to the top, then its background appears upon scrolling down. This works if it can find a scroll view in the view hierarchy.
In my app, it's possible for the user to scroll down causing the navigation bar background to be visible, and then they could perform an action which ultimately causes the scroll view to be removed from the view hierarchy. The problem is the navigation bar is not updated to be transparent again.
How can one trigger the navigation bar to be redrawn as a result of the scroll view being removed from screen? I have tried
navigationController?.navigationBar.scrollEdgeAppearance = nil
navigationController?.navigationBar.setNeedsDisplay()
navigationController?.navigationBar.setNeedsLayout()
navigationController?.navigationBar.layoutIfNeeded()
but this unfortunately didn't do the trick - the background stays visible.
I stumbled upon a solution on Twitter! Thanks for tweeting David Duncan.
Put this in your view controller when the scroll view is removed from the view hierarchy:
//update navigation bar appearance now that the scroll view is gone
setContentScrollView(UIScrollView(), for: .top)
setContentScrollView(nil, for: .top)
Update: This worked in iOS 15.0 beta 5 but has not worked since, tested up to 15.2. I filed a bug report.
Another solution is to get the content scroll view and scroll it to the top before removing it from the view hierarchy:
if let scrollView = contentScrollView(for: .top) {
scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.contentInset.top), animated: false)
}