UINavigationBar change colors on push
To achieve this kind of animation you should use UIViewControllerTransitionCoordinator
as Apple documentation say it is :
An object that adopts the UIViewControllerTransitionCoordinator protocol provides support for animations associated with a view controller transition.(...)
So every UIViewController
has own transitionController
. To get this you should call in the UIViewControllerClass
:
self.transitionCoordinator()
From documentation:
Returns the active transition coordinator object.
So to get the result that you want you should implement animateAlongsideTransition
method in viewController transitionCoordinatior. Animation works when you click backButton
and swipe to back.
Example :
First Controller :
class ViewControllerA: UIViewController { override func loadView() { super.loadView() title = "A" view.backgroundColor = .white navigationItem.rightBarButtonItem = UIBarButtonItem(title: "NEXT", style: .plain, target: self, action: #selector(self.showController)) setColors() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) animate() } func showController() { navigationController?.pushViewController(ViewControllerB(), animated: true) } private func animate() { guard let coordinator = self.transitionCoordinator else { return } coordinator.animate(alongsideTransition: { [weak self] context in self?.setColors() }, completion: nil) } private func setColors() { navigationController?.navigationBar.tintColor = .black navigationController?.navigationBar.barTintColor = .red }}
Second Controller:
class ViewControllerB : UIViewController { override func loadView() { super.loadView() title = "B" view.backgroundColor = .white setColors() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) animate() } override func willMove(toParentViewController parent: UIViewController?) { // tricky part in iOS 10 navigationController?.navigationBar.barTintColor = .red //previous color super.willMove(toParentViewController: parent) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) navigationController?.navigationBar.barTintColor = .blue } private func animate() { guard let coordinator = self.transitionCoordinator else { return } coordinator.animate(alongsideTransition: { [weak self] context in self?.setColors() }, completion: nil) } private func setColors(){ navigationController?.navigationBar.tintColor = .black navigationController?.navigationBar.barTintColor = .blue }}
UPDATE iOS 10
In the iOS 10 the tricky part is to add the willMoveTo(parentViewController parent: UIViewController?)
in the second ViewController. And set the navigationBar tintColor
to the color value of previous controller. Also, in viewDidAppear
method in second ViewControler set the navigationBar.tintColor
to the color from second viewController.
Check out my example project on github
I've coded final solution that looks most comfortable to use (don't need to use a lot of overrides in own view controllers). It works perfectly at iOS 10 and easy adoptable for own purposes.
GitHub
You can check GitHub Gist for full class code and more detailed guide, I won't post full code here because Stackoverflow is not intended for storing a lot of code.
Usage
Download Swift file for GitHub. To make it work just use ColorableNavigationController
instead of UINavigationController
and adopt needed child view controllers to NavigationBarColorable
protocol.
Example:
class ViewControllerA: UIViewController, NavigationBarColorable { public var navigationBarTintColor: UIColor? { return UIColor.blue } override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Push", style: .plain, target: self, action: #selector(self.showController)) } func showController() { navigationController?.pushViewController(ViewControllerB(), animated: true) }}class ViewControllerB: UIViewController, NavigationBarColorable { public var navigationBarTintColor: UIColor? { return UIColor.red }}let navigationController = ColorableNavigationController(rootViewController: ViewControllerA())
This worked for me:
override func willMove(toParent parent: UIViewController?) { super.willMove(toParent: parent) navigationController?.navigationBar.barTintColor = previous view controller's navigation bar color }