如何转换/动画UINavigationBar的颜色?

Sti*_*Sti 30 uiviewcontroller uiview ios

我一直在寻找如何过渡/动画barTintColorUINavigationBar现在一段时间,我只看到不同的答案.一些使用UIView.animateWithDuration,一些使用CATransition,但最有趣的,像这一个使用animate(alongsideTransition animation..,我喜欢的声音,但我不能让它正常工作.难道我做错了什么?

许多人指出我可以简单地使用transitionCoordinatorin viewWillAppear:.我已经建立了一个像这样的新超级小项目:

class RootViewController:UIViewController{ //Only subclassed
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
            self?.setNavigationColors()
            }, completion: nil)
    }
    func setNavigationColors(){
        //Override in subclasses
    }
}

class FirstViewController: RootViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "First"
    }
    override func setNavigationColors(){
        navigationController?.navigationBar.barTintColor = UIColor.white
        navigationController?.navigationBar.tintColor = UIColor.black
        navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.black]
        navigationController?.navigationBar.barStyle = UIBarStyle.default
    }
}
class SecondViewController: RootViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "Second"
    }
    override func setNavigationColors(){
        navigationController?.navigationBar.barTintColor = UIColor.black
        navigationController?.navigationBar.tintColor = UIColor.white
        navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        navigationController?.navigationBar.barStyle = UIBarStyle.black
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,会发生以下情况: 第一

  • 从推动过渡FirstSecond看起来很完美.所有元素都完美过渡,可能除了StatusBar,它立即变为白色.我宁愿知道如何转换它,但我现在会接受它.
  • 流行音乐从过渡SecondFirst完全错误.它保持颜色,Second直到转换完成.
  • 拖动过渡时,拖动过渡SecondFirst看起来没问题.再次,一旦我开始拖动,StatusBar立即变黑,但我不知道是否可以修复.
  • 拖动过渡SecondFirst但是取消了中间拖动并返回到Second完全搞砸了.它看起来很好,直到Second完全恢复控制,然后突然变为First-colors.这不应该发生.

我对我做了一些改动,RootViewController以使它更好一些.我viewWillAppear:完全删除了,并改为:

class RootViewController:UIViewController{

    override func willMove(toParentViewController parent: UIViewController?) {
        if let last = self.navigationController?.viewControllers.last as? RootViewController{
            if last == self && self.navigationController!.viewControllers.count > 1{
                if let parent = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - 2] as? RootViewController{
                    parent.setNavigationColors()
                }
            }
        }
    }
    override func viewWillDisappear(_ animated: Bool) {
        if let parent = navigationController?.viewControllers.last as? RootViewController{
            parent.animateNavigationColors()
        }
    }
    override func viewDidAppear(_ animated: Bool) {
        self.setNavigationColors()
    }

    func animateNavigationColors(){
        transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
            self?.setNavigationColors()
            }, completion: nil)
    }
    func setNavigationColors(){
        //Override in subclasses
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个更新的代码,我得到这个: 第二

一些观察:

  • 从过渡FirstSecond是相同的
  • 从弹出式过渡SecondFirst现在的动画正确,只是从后面箭头,后面文本(和状态栏,但是啊..).这些立即变为黑色.在第一个gif中,您可以看到后箭头和后退文本也已转换.
  • 从拖动过渡SecondFirst也有这个问题,启动时背箭头,背文突然瞬间变黑.barTint是固定的,因此在取消拖动时不会出现错误的颜色.

我究竟做错了什么?我该怎么做?

我想要的是顺利过渡所有元素.后退按钮,后退文本,标题,barTint和statusBar的色调.这不可能吗?

Jos*_*had 10

在此输入图像描述

在10 iOS中,它工作不完美:(

将导航控制器子类化为使用可见视图控制器的statusbarstyle:

class MyNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return visibleViewController!.preferredStatusBarStyle
    }
}
Run Code Online (Sandbox Code Playgroud)

覆盖Root控制器中的preferredStatusBarStyle并添加函数以弹出动画之前设置样式:

private var _preferredStyle = UIStatusBarStyle.default;
override var preferredStatusBarStyle: UIStatusBarStyle {
    get {
        return _preferredStyle
    }
    set {
        _preferredStyle = newValue
        self.setNeedsStatusBarAppearanceUpdate()
    }

}


func animateNavigationColors(){
        self.setBeforePopNavigationColors()
        transitionCoordinator?.animate(alongsideTransition: { [weak self](context) in
            self?.setNavigationColors()
            }, completion: nil)
    }

func setBeforePopNavigationColors() {
    //Override in subclasses
}
Run Code Online (Sandbox Code Playgroud)

在第一个控制器:

override func setBeforePopNavigationColors() {
    navigationController?.navigationBar.tintColor = UIColor.white
    navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
    self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
}

override func setNavigationColors(){
    navigationController?.navigationBar.barTintColor = UIColor.white
    navigationController?.navigationBar.tintColor = UIColor.black
    navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
    navigationController?.navigationBar.barStyle = UIBarStyle.default
    self.preferredStatusBarStyle = UIStatusBarStyle.default
}
Run Code Online (Sandbox Code Playgroud)

第二个:

  override func setNavigationColors(){
        navigationController?.navigationBar.barTintColor = UIColor.black
        navigationController?.navigationBar.tintColor = UIColor.white
        navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
        navigationController?.navigationBar.barStyle = UIBarStyle.black
        self.preferredStatusBarStyle = UIStatusBarStyle.lightContent
    }
Run Code Online (Sandbox Code Playgroud)

示例项目:https://github.com/josshad/TestNavBarTransition

  • 尽管此链接可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。如果将来其他问题/答案被删除,则仅链接的答案可能会失效。 (2认同)

cle*_*ens 2

您可以覆盖push和pop方法来UINavigationController设置条形颜色。我已将与视图控制器相对应的条形颜色存储在其导航项中,并使用UINavigationItem. 以下代码适用于 iOS 11 中的完整过渡和交互式过渡:

import UIKit

class NavigationItem: UINavigationItem {
    @IBInspectable public var barTintColor: UIColor?
}

class NavigationController: UINavigationController, UIGestureRecognizerDelegate {
    func applyTint(_ navigationItem: UINavigationItem?) {
        if let item = navigationItem as? NavigationItem {
            self.navigationBar.barTintColor = item.barTintColor
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        applyTint(self.topViewController?.navigationItem)
        self.interactivePopGestureRecognizer?.delegate = self
    }
    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        applyTint(viewController.navigationItem)
        super.pushViewController(viewController, animated: animated)
    }

    override func popViewController(animated: Bool) -> UIViewController? {
        let viewController = super.popViewController(animated: animated)

        applyTint(self.topViewController?.navigationItem)
        return viewController
    }

    override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
        let result = super.popToViewController(viewController, animated: animated)

        applyTint(viewController.navigationItem)
        return result
    }

    override func popToRootViewController(animated: Bool) -> [UIViewController]? {
        let result = super.popToRootViewController(animated: animated)

        applyTint(self.topViewController?.navigationItem)
        return result
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return (otherGestureRecognizer is UIScreenEdgePanGestureRecognizer)
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:颜色动画的协调是由导航控制器完成的