Animate a UINavigationBar's barTintColor

前端 未结 3 1380
[愿得一人]
[愿得一人] 2021-02-02 04:22

The app I\'m working on changes the barTintColor of its navigation bar when pushing new view controllers. Right now we set that colour in the destination view contr

3条回答
  •  北恋
    北恋 (楼主)
    2021-02-02 04:37

    To get a smooth animation during both push and pop, I had to make the navigation bar transparent and animate my own background color view behind it.

    Here's my UINavigationController subclass that handles it:

    import Foundation
    import UIKit
    
    class ColorTransitionNavigationController: UINavigationController {
    
        var navigationBarBackgroundView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Put a background view behind the navigation bar
            navigationBarBackgroundView = UIView()
            view.insertSubview(navigationBarBackgroundView, belowSubview: navigationBar)
    
            // Make the navigation bar transparent
            navigationBar.isTranslucent = true
            navigationBar.setBackgroundImage(UIImage(), for: .default)
    
            // Size the colored background to match the navigation bar
            navigationBarBackgroundView.translatesAutoresizingMaskIntoConstraints = false
            navigationBarBackgroundView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            navigationBarBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            navigationBarBackgroundView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    
            // I used a hard-coded 64 instead of constraining to the height of the navigation bar because
            // when calling navigationController.setNavigationBarHidden(true), the height of the navigation bar becomes 0
            navigationBarBackgroundView.heightAnchor.constraint(equalToConstant: 64.0).isActive = true
    
        }
    
        func setBarTintColor(color: UIColor, animated: Bool, transitionCoordinator: UIViewControllerTransitionCoordinator?) {
            guard let transitionCoordinator = transitionCoordinator, animated else {
                navigationBarBackgroundView.backgroundColor = color
                return
            }
    
            transitionCoordinator.animateAlongsideTransition(in: view, animation: { [weak self] (context) in
    
                let transition = CATransition()
                transition.duration = context.transitionDuration
                transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
                self?.navigationBarBackgroundView.layer.add(transition, forKey: nil)
                self?.navigationBarBackgroundView.backgroundColor = color
    
            }, completion:nil)
        }
    }
    

    Usage:

    If you want a UIViewController to animate the navigation bar color when it appears, override viewWillAppear and call setBarTintColor.

    override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            guard let navigationController = navigationController as? ColorTransitionNavigationController else { return }
            navigationController.setBarTintColor(color: UIColor.green, animated: animated, transitionCoordinator: transitionCoordinator)
        }
    

提交回复
热议问题