Animate a UINavigationBar's barTintColor

前端 未结 3 1378
[愿得一人]
[愿得一人] 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

    Here is a simpler fix. The issue with barTintColor not animating correctly on pop occurs when you try to set the navigation bar appearance in viewWillDisappear. The fix is to set it in willMove(toParentViewController:) instead.

    The code below will produce a smooth fading transition during both push and pop, and regardless of whether it is initiated by a gesture or button tap. Tested on iOS 10 and 11.

    This also works for animating barStyle.

    import UIKit
    
    class RedViewController: UIViewController {
    
        override func viewWillAppear(_ animated: Bool) {
            self.title = "Red"
            self.navigationController?.navigationBar.barTintColor = .red
            self.navigationController?.navigationBar.tintColor = .white
        }
    
        override func willMove(toParentViewController parent: UIViewController?) {
            self.navigationController?.navigationBar.barTintColor = .white
            self.navigationController?.navigationBar.tintColor = nil
        }
    }
    
    0 讨论(0)
  • 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)
        }
    
    0 讨论(0)
  • 2021-02-02 04:54

    You can add extra animations that match the timing and animation curve of the view controller transition using UIViewControllerTransitionCoordinator.

    A view controller's transitionCoordinator will be set after a view controller's animation has started (so in viewWillAppear of the presented view controller). Add any extra animations using animateAlongsideTransition:completion: on the transition coordinator.

    An example:

    [[self transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        self.navigationController.navigationBar.translucent = NO;
        self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
        self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
        self.navigationController.navigationBar.barTintColor = [UIColor redColor];
    } completion:nil];
    
    0 讨论(0)
提交回复
热议问题