Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UINavigationBar change colors on push

Tags:

I'm using 2 different bar tint colors at UINavigationBar in different views. I'n changing color with that method in both views:

override func viewWillAppear(animated: Bool) {     super.viewWillAppear(animated)     self.navigationController?.navigationBar.barTintColor = COLOR } 

When I tap on back button color is not changed smoothly (you can see blink on last second).

Visual bug

But everything is okay if just swipe view back instead of tapping on back button.

No visual bug

How to make smooth transition in both situations?

like image 781
Vasily Avatar asked Oct 25 '16 14:10

Vasily


People also ask

How do I change the background on my navigation bar?

In order to change the hub navigation bar color, we can go to site settings of hub site>Change the look>under the header section>Background> select a theme color to change the background color of your site header.

How do I change the navigation bar on my Iphone?

Change the Bar Style A user changes the navigation bar's style, or UIBarStyle , by tapping the “Style” button to the left of the main page. This button opens an action sheet where users can change the background's appearance to default, black-opaque, or black- translucent.


2 Answers

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 :

navigation_bar_animation

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

like image 67
kamwysoc Avatar answered Oct 03 '22 14:10

kamwysoc


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()) 
like image 37
Vasily Avatar answered Oct 03 '22 14:10

Vasily