更新视图控制器之间的状态栏样式

Updating the status bar style between view controllers

在我的 info.plist 文件中,我将 View controller-based status bar appearance 设置为 YES

我有一个 FirstViewController 隐藏了状态栏。

在我的 SecondViewController 我有

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

override var prefersStatusBarHidden: Bool {
    return false
}

override func viewDidLoad() {
    super.viewDidLoad()

    setNeedsStatusBarAppearanceUpdate()
}

然而,状态栏出现了,但是是黑色的。

如何让它正确更新?谢谢

编辑:

AppDelegate.swift也有这个

UIApplication.shared.statusBarStyle = .lightContentdidFinishLaunchingWithOptions

Info.plist 文件中有一个 属性 名为 View controller-based status bar appearance。它应该设置为 YES。 然后在你的 UIViewController 中你应该覆盖 preferredStatusBarStyle:

override var preferredStatusBarStyle : UIStatusBarStyle {
    return .lightContent
}

这里有一件需要注意的重要事情:如果您将视图控制器嵌入到 UINavigationController 中并且您的视图控制器的 preferredStatusBarStyle 方法未被调用 - 您将不得不通过编写如下内容来解决它:

extension UINavigationController {
    override open var preferredStatusBarStyle : UIStatusBarStyle {
        return topViewController?.preferredStatusBarStyle ?? .default
    }
}

它所做的只是向顶部控制器询问它的状态栏样式,并适当地更新

当您的视图控制器是导航控制器的子级时,关于如何管理状态栏样式存在大量误解。

您的子视图控制器可以实现 preferredStatusBarStyle,如果导航栏 隐藏 ,这将正常工作。

如果导航栏显示,导航控制器根据导航栏的barStyle设置状态栏样式——如果导航栏为.default样式为 .default,如果栏样式为 .black,则为 .lightContent。因此,当导航栏显示时,视图控制器设置状态栏样式的正确方法是设置导航控制器的导航栏样式。

执行此操作的明显位置是在 viewWillAppear 中,每当此视图控制器成为导航控制器堆栈的顶部时调用它:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.navigationBar.barStyle = .black // or .default
}

UINavigationController 有一个替代解决方案。您可以将其子类化并结合使用 childForStatusBarHidden 属性 和 setNeedsStatusBarAppearanceUpdate().

class StatusBarNavigationController: UINavigationController {
    override var childForStatusBarHidden: UIViewController? {
        return topViewController
    }

    override var viewControllers: [UIViewController] {
        didSet { setNeedsStatusBarAppearanceUpdate() }
    }
}

因此状态栏样式将由topViewController定义。

Swift5,iOS12

这里的大部分答案都有帮助,但并没有立即解决我的问题。我有一个嵌套结构(root VC > tab bar VC > navigation VC > specific page VC)我想要一个推送页面 VCs更改状态栏颜色。

在页面 VC 中设置 navigationBar.barStyle 对我没有任何作用,可能是因为导航 VC 不是顶级 VC。设置 preferredStatusBarStyle 在页面 VC 中也不起作用(尽管如果我在根 VC 中覆盖此 属性 它确实起作用)。

@kelin 的回答让我走上了正确的方向。 childForStatusBarStyle 有助于指定应检查哪些 child VC 以获取正确的样式。以下是我采取的步骤:

第 1 步:为我的 VC 层次结构中的所有 VC 实施 childForStatusBarHidden

例如对于根 VC

override var childForStatusBarStyle: UIViewController? {
  // this is a custom var I've set up
  return currentViewController
}

对于选项卡 VC

override var childForStatusBarStyle: UIViewController? {
  return selectedViewController
}

用于导航 VC

override var childForStatusBarStyle: UIViewController? {
  return topViewController
}

第2步:确保正确调用了childForStatusBarStyle。我的根 VC 的 currentViewController 变量在 iOS 检查之前没有设置,所以我需要在设置该变量后调用 setNeedsStatusBarAppearanceUpdate() 以指示 childForStatusBarStyle需要再次检查。

第三步:在childVC判断状态栏外观,覆盖样式:

override var preferredStatusBarStyle: UIStatusBarStyle {
  return .lightContent
}

步骤4:确保在创建child VC时调用setNeedsStatusBarAppearanceUpdate(),并从根控制器调用它。因此,child VC 中的 setNeedsStatusBarAppearanceUpdate() 不起作用,但是例如UIApplication.shared.keyWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate() 做到了。

第5步:当childVC从层次结构中移除并且你想恢复状态栏样式时,一定要调用setNeedsStatusBarAppearanceUpdate() 再次从根 VC 开始,也许在 viewWillDisappear.

附带说明一下,上述解决方案不需要我将 View controller-based status bar appearance Info.plist 值显式设置为 YES 许多答案引用。