UINavigationBar change colors on push

后端 未结 4 1953
长情又很酷
长情又很酷 2020-12-23 17:49

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          


        
相关标签:
4条回答
  • 2020-12-23 17:57

    This worked for me:

     override func willMove(toParent parent: UIViewController?) {
          super.willMove(toParent: parent)
          navigationController?.navigationBar.barTintColor = previous view controller's navigation bar color
     }
    
    0 讨论(0)
  • 2020-12-23 17:58

    I am just wondering. For the same purpose I use UINavigationControllerDelegate. In navigationController(_:willShow:) I start the animation using transitionCoordinator?.animate(alongsideTransition:completion:). It works great when pushing new controllers, however pop doesn't.

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
      let dst = viewController as! ViewController
      guard animated else {
        navigationController.navigationBar.barTintColor = dst.navigationBarColor
        navigationController.navigationBar.tintColor = dst.tintColor
        navigationController.navigationBar.barStyle = dst.barStyle
        return
      }
    
      navigationController.transitionCoordinator?.animate(alongsideTransition: { context in
        navigationController.navigationBar.barTintColor = dst.navigationBarColor
        navigationController.navigationBar.tintColor = dst.tintColor
        navigationController.navigationBar.barStyle = dst.barStyle
      }, completion: { context in
        if context.isCancelled {
          let source = context.viewController(forKey: UITransitionContextViewControllerKey.from) as! ViewController
            navigationController.navigationBar.barTintColor = source.navigationBarColor
            navigationController.navigationBar.tintColor = source.tintColor
            navigationController.navigationBar.barStyle = source.barStyle
        }
    })
    

    Do you see any reason why it should work with pushes but not pops?

    0 讨论(0)
  • 2020-12-23 18:02

    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

    0 讨论(0)
  • 2020-12-23 18:12

    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())
    
    0 讨论(0)
提交回复
热议问题