【问题标题】:Animate a UINavigationBar's barTintColor为 UINavigationBar 的 barTintColor 设置动画
【发布时间】:2014-02-06 04:03:54
【问题描述】:

我正在开发的应用程序在推送新的视图控制器时会更改其导航栏的barTintColor。现在我们在目标视图控制器的viewWillAppear:方法中设置了该颜色,但我们有一些问题。

按照我们现在的做法,导航栏的颜色会突然改变,而导航栏的其余内容则照常进行动画处理。我想要的是条在源颜色和目标颜色之间褪色。有没有办法通过公共 Cocoa Touch API 实现这一点?

【问题讨论】:

    标签: objective-c ios7 uinavigationcontroller uinavigationbar


    【解决方案1】:

    您可以使用UIViewControllerTransitionCoordinator 添加与视图控制器转换的时间和动画曲线相匹配的额外动画。

    视图控制器的transitionCoordinator 将在视图控制器的动画开始后设置(因此在所呈现视图控制器的viewWillAppear 中)。在过渡协调器上使用 animateAlongsideTransition:completion: 添加任何额外的动画。

    一个例子:

    [[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];
    

    【讨论】:

    • 这在 iOS 9 和 10 上不起作用。它只是直接切换颜色。关于它在 prepareForSegue 中起作用的事实非常奇怪
    • 这适用于我在 iOS10 中推送期间但不弹出(对于弹出,它在弹出动画后直接切换颜色)
    • @Happiehappie 是的,但我必须以一种 hacky 的方式来获得我想要的结果。发布以防它对任何人有用。 stackoverflow.com/a/42405212/1575848
    【解决方案2】:

    这是一个更简单的解决方法。当您尝试在viewWillDisappear 中设置导航栏外观时,会出现barTintColor 在弹出时无法正确动画的问题。解决方法是将其设置为 willMove(toParentViewController:)。

    下面的代码将在 push 和 pop 期间产生平滑的淡入淡出过渡,无论它是由手势还是按钮点击启动的。在 iOS 10 和 11 上测试。

    这也适用于动画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
        }
    }
    

    【讨论】:

    • 这应该是正确的答案。简洁大方!
    【解决方案3】:

    为了在 push 和 pop 期间获得流畅的动画,我必须使导航栏透明并在其后面设置我自己的背景颜色视图。

    这是处理它的 UINavigationController 子类:

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

    用法:

    如果您希望 UIViewController 在导航栏出现时对其颜色进行动画处理,请覆盖 viewWillAppear 并调用 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)
        }
    

    【讨论】:

    • 你是否也让它与标题颜色一起使用?
    • 很遗憾,我不记得了,我想我没有尝试过更改标题颜色。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-05
    相关资源
    最近更新 更多