UINavigationBar在推动时改变颜色

UINavigationBar在不同的视图中使用了2种不同的色调颜色。 这两种观点都是用这种方法改变颜色的:

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

当我点击后退button时,颜色没有平滑地变化(你可以看到最后一秒闪烁)。

视觉错误

但是,如果只是向后滑动视图而不是点击后退button,一切都可以。

没有视觉错误

如何在两种情况下平滑过渡?

要实现这种animation,你应该使用UIViewControllerTransitionCoordinator正如苹果文档所说的那样:

采用UIViewControllerTransitionCoordinator协议的对象支持与视图控制器转换关联的animation(…)

所以每个UIViewController都有自己的transitionController 。 为了得到这个,你应该调用UIViewControllerClass

self.transitionCoordinator()

从文档 :

返回活动的过渡协调器对象。

所以要得到你想要的结果,你应该在viewController transitionCoordinatior中实现animateAlongsideTransition方法。 点击backButton并滑动返回时,animation将起作用。

例如:

navigation_bar_animation

第一控制器:

 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 } } 

第二控制器:

 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) { 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 } } 

更新iOS 10

在iOS 10中,棘手的部分是在第二个 ViewController中添加willMoveTo(parentViewController parent: UIViewController?) 。 并将navigationBar tintColor设置为前一个控制器的颜色值。 另外,在第二个 ViewControler的viewDidAppear方法中,将navigationBar.tintColor设置为第二个 viewController的颜色。

看看我的github上的示例项目

我已经编写了最终的解决scheme,看起来最舒适的使用(不需要在自己的视图控制器中使用大量的覆盖)。 它可以在iOS 10中完美运行,并且可以轻松地用于自己的目的。

GitHub上

你可以检查GitHub Gist的全class代码和更详细的指南,我不会在这里发布完整的代码,因为Stackoverflow不是用来存储大量的代码。

用法

下载GitHub的Swift文件。 为了使它工作,只需使用ColorableNavigationController而不是UINavigationController并将需要的子视图控制器ColorableNavigationController NavigationBarColorable协议。

例:

 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())