为UINavigationBar的barTintColor设置动画

时间:2014-02-06 04:03:54

标签: objective-c ios7 uinavigationcontroller uinavigationbar

我正在处理的应用在推送新视图控制器时会更改其导航栏的barTintColor。现在我们在目标视图控制器的viewWillAppear:方法中设置了这种颜色,但是我们遇到了一些问题。

按照我们现在这样做的方式,导航栏的颜色会突然变化,而其余的条形内容会像往常一样动画。我喜欢的是酒吧在源颜色和目标颜色之间淡入淡出。有没有办法用公共Cocoa Touch API实现这一目标?

3 个答案:

答案 0 :(得分:17)

您可以使用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];

答案 1 :(得分:1)

为了在推送和弹出期间获得平滑的动画,我必须使导航栏透明,并在其背后为我自己的背景颜色视图设置动画。

这是我处理它的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)
    }

答案 2 :(得分:1)

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

以下代码将在推送和弹出期间产生平滑的淡入淡出过渡,无论是通过手势还是按钮按钮启动。在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
    }
}