BarTintColor navigation bar animation change in iOS10 not working

I upgraded to Xcode 8.0 / iOS 10, and now the color change animation of my navigation bar no longer works, it changes color directly without animation.

UIView.animateWithDuration(0.2, animations: { self.navigationController?.navigationBar.barTintColor = currentSection.color! }) 

Does anyone know how to fix this?

+10
ios ios10 swift2
source share
2 answers

To animate the navigation color change in the iOS10 browser, you need to call layoutIfNeeded after setting the color inside the animation block.

Code example:

 UIView.animateWithDuration(0.5) { self.navigationController?.navigationBar.barTintColor = UIColor.redColor() self.navigationController?.navigationBar.layoutIfNeeded() } 

I also want to report that Apple does not support official support in properties such as barTintColor, so the method may be interrupted at any time.

If you call -layoutIfNeeded on the navigation bar during the animation, the block should update its background properties, but given the nature of what these properties do, there really has never been any that you can animate any of them.

+29
source share

Interactive animation

Interactive animation

Define a protocol:

 /// Navigation bar colors for 'ColorableNavigationController', called on 'push' & 'pop' actions public protocol NavigationBarColorable: UIViewController { var navigationTintColor: UIColor? { get } var navigationBarTintColor: UIColor? { get } } public extension NavigationBarColorable { var navigationTintColor: UIColor? { return nil } } 

Define a custom subclass of NavigationController :

 class AppNavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() navigationBar.shadowImage = UIImage() if let colors = rootViewController as? NavigationBarColorable { setNavigationBarColors(colors) } } private var previousViewController: UIViewController? { guard viewControllers.count > 1 else { return nil } return viewControllers[viewControllers.count - 2] } override open func pushViewController(_ viewController: UIViewController, animated: Bool) { if let colors = viewController as? NavigationBarColorable { setNavigationBarColors(colors) } super.pushViewController(viewController, animated: animated) } override open func popViewController(animated: Bool) -> UIViewController? { if let colors = previousViewController as? NavigationBarColorable { setNavigationBarColors(colors) } // Let start pop action or we can't get transitionCoordinator() let popViewController = super.popViewController(animated: animated) // Secure situation if user cancelled transition transitionCoordinator?.animate(alongsideTransition: nil, completion: { [weak self] context in guard let 'self' = self else { return } guard let colors = self.topViewController as? NavigationBarColorable else { return } self.setNavigationBarColors(colors) }) return popViewController } override func popToRootViewController(animated: Bool) -> [UIViewController]? { if let colors = rootViewController as? NavigationBarColorable { setNavigationBarColors(colors) } let controllers = super.popToRootViewController(animated: animated) return controllers } private func setNavigationBarColors(_ colors: NavigationBarColorable) { if let tintColor = colors.navigationTintColor { navigationBar.titleTextAttributes = [ .foregroundColor : tintColor ] navigationBar.tintColor = tintColor } navigationBar.barTintColor = colors.navigationBarTintColor } } 

Now you can match the NavigationBarColorable in any controller inside the AppNavigationController and assign it whatever color you want.

 extension FirstViewController: NavigationBarColorable { public var navigationBarTintColor: UIColor? { UIColor.red } public var navigationTintColor: UIColor? { UIColor.white } } extension SecondViewController: NavigationBarColorable { public var navigationBarTintColor: UIColor? { UIColor.blue } public var navigationTintColor: UIColor? { UIColor.orange } } 

Remember to implement this useful extension:

 extension UINavigationController { var rootViewController: UIViewController? { return viewControllers.first } } 
0
source share

All Articles