Reputation: 683
In an app I am working on, I have a UITabBarController
that contains views that are each in a UINavigationController
.
One of the views is a settings screen where a user can change the color scheme of the app. When they do so, and switch to another screen, every component that is supposed to change color is already changed EXCEPT for the background of the UINavigationController
. It updates a fraction of a second after it is visible, so there is an annoying flicker.
This is a simplification of my viewWillAppear
(which I just tested to make sure it still causes the error)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIColor *foreGround = [self.settings getForegroundColor];
UIColor *backGround = [self.settings getBackgroundColor];
self.navigationController.navigationBar.barTintColor = backGround;
self.navigationController.tabBarController.tabBar.barTintColor = backGround;
self.view.backgroundColor = backGround;
self.navigationController.navigationBar.tintColor = foreGround;
self.navigationController.tabBarController.tabBar.tintColor = foreGround;
self.view.tintColor = foreGround;
}
What is even stranger, I have a UIBarButtonItem
in the UINavigationController
Bar that I go to, and it's color has updated before the view is visible, but the background behind it still needs to update.
Things I have tried:
[self.view setNeedsDisplay];
[self.navigationController.navigationBar setNeedsDisplay];
viewWillLayoutSubviews
NSNotification
that is sent to the this viewController when the user changed the color setting (long before they click the tab bar to look at the offending viewController).Is there a way to force it to draw off screen, or something so This flicker won't occur? I do not understand why it is insisting on updating when visible, when I put this in the main viewController's viewWIllAppear
.
Does anybody know how to make a UINavigationController's Bar update before coming onscreen when the UINavigationController is embedded in a tab bar controller?
Upvotes: 3
Views: 814
Reputation: 131
You need to use the UINavigationControllerDelegate
. Here is a snippet in Swift from my app that should work:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
reloadNav()
}
func reloadNav() {
//Put custom code to change UINavigationController however you want.
//Animation is not necessary, but it is nice.
UIView.animate(withDuration: 0.35) {
self.navigationController?.navigationBar.barTintColor = nil
//This is the default iOS tint color
self.navigationController?.navigationBar.tintColor = #colorLiteral(red: 0.2901960784, green: 0.5019607843, blue: 0.9019607843, alpha: 1)
self.navigationController?.navigationBar.barStyle = .default
}
}
}
extension ViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if let vc2 = toVC as? ViewController {
vc2.reloadNav()
}
return nil
}
}
TL;DR Use the func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
in the UINavigationControllerDelegate
to perform your custom animation by accessing the reload func in your view controller.
I hope this helps, let me know if you need more clarification/help. Good luck!
Upvotes: 1