NavigationBar延迟更新barTintColor iOS10

时间:2016-10-03 15:42:14

标签: objective-c swift uinavigationbar ios10

上下文

假设我们有一个NavigationController和两个viewControllers。 ViewControllerA有一个蓝色的navigationBar,而ViewControllerB有一个绿色的。

我这样设置:

override func viewWillAppear(_ animated: Bool) {
        self.navigationController?.navigationBar.barTintColor = UIColor.blue    // Green if ViewController B
    }

当我从A到B时,它运作良好,但是当我返回时,navigationBar teint会在之后更新。就像它是在viewDidAppear中设置的那样。

预期:

导航栏的导航栏颜色应立即更新。

已尝试解决方案:

  • 我看过这篇SO帖子,我尝试了解决方案。它有效,但会使导航栏的管理变得更加复杂和痛苦。 (在一个真实的应用程序中)

  • 我尝试在ViewWillDisappear方法中更改导航栏提示。没用。

更多:

这是由ios10 API的更改引起的。我已经阅读了release notes,但目前还不清楚在这种情况下应该做些什么。

  

在iOS 10中,UIKit已经更新并统一了后台管理   UINavigationBar,UITabBar和UIToolbar。特别是改变了   这些视图的背景属性(例如背景或阴影   图像,或设置栏样式)可以启动布局传递   栏来解决新的背景外观。

     

特别是这个   意味着尝试更改这些条的背景外观   在layoutSubviews中, - [UIView updateConstraints],   viewWillLayoutSubviews,viewDidLayoutSubviews,updateViewConstraints,   或者可能导致响应布局而调用的任何其他方法   布局循环。

     

在某些情况下,您可以通过确保您来打破这些布局循环   在对象(例如UIImage或。)时始终使用相同的对象实例   UIColor)是必需的。但总的来说,你应该避免这样做。

问题:

在iOS 10中处理不同导航控制器之间导航栏更改的最佳方法是什么?

2 个答案:

答案 0 :(得分:11)

试试这段代码:

注意:代码在Swift 3中测试。

在ViewController A中:

    override var isViewLoaded: Bool {
    title = "View 1"
    navigationController?.navigationBar.barTintColor = .blue
    navigationController?.navigationBar.isTranslucent = true
    navigationController?.navigationBar.tintColor = UIColor.white
    navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
    UIApplication.shared.statusBarStyle = .lightContent
    self.navigationController?.navigationBar.barStyle = .black // In case statusbar Light content wont work.
    return true
    }

在ViewController B中:

    override var isViewLoaded: Bool {
    title = "View 2"
    navigationController?.navigationBar.barTintColor = .green
    navigationController?.navigationBar.tintColor = .white
    navigationController?.navigationBar.isTranslucent = true
    navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
    return true
    }

输出:没有任何延迟......

enter image description here

图案图片为TintColor。

在ViewController A中:

 navigationController?.navigationBar.barTintColor = UIColor(patternImage: UIImage(named: "viewOneImage.jpg")!)

在ViewController B中:

 navigationController?.navigationBar.barTintColor = UIColor(patternImage: UIImage(named: "viewTwoImage.jpg")!)

输出:

enter image description here

答案 1 :(得分:0)

我对覆盖isViewLoaded的解决方案不满意,因为如果有时间显示view_controller_a,并且出于任何原因使用view_controller_b.isViewLoaded的值,那么您将结束向上将导航栏更改为错误的显示。

相反,我会将所需的导航栏配置存储在每个视图控制器中,并使用UINavigationControllerDelegate

class NavBarConfig
{
    var background_color: UIColor

    init( background_color: UIColor )
    {
        self.background_color = background_color
    }
}

class ViewController: UIViewController
{
    var nav_bar_config: NavBarConfig?
}

class NavControllerDelegate: UINavigationControllerDelegate
{
    //Called just before the navigation controller displays a view controller’s view and navigation item properties.
    func navigationController( _ nav_controller: UINavigationController, willShow view_controller: UIViewController, animated: Bool )
    {
        if let view_controller = view_controller as? ViewController, let nar_bar_config = view_controller.nav_bar_config
        {
            nav_controller.navigationBar.barTintColor = view_controller.nar_bar_config.background_color
        }
    }
}

在导航控制器your_nav_controller.delegate = NavControllerDelegate()上设置委托后,将在显示每个视图控制器之前调用委托方法,使您可以按自己的意愿配置导航栏。