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

Posted

技术标签:

【中文标题】更新视图控制器之间的状态栏样式【英文标题】:Updating the status bar style between view controllers 【发布时间】:2018-05-29 23:53:19 【问题描述】:

在我的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 = .lightContent in didFinishLaunchingWithOptions

【问题讨论】:

【参考方案1】:

Info.plist 文件中有一个名为查看基于控制器的状态栏外观的属性。它应该设置为YES。 然后在你的 UIViewController 中你应该覆盖 preferredStatusBarStyle:

override var preferredStatusBarStyle : UIStatusBarStyle 
    return .lightContent

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

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

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

【讨论】:

谢谢瓦莱里。该扩展是我整个上午都在这里寻找的答案 @ZackShapiro 在导航控制器的子视图控制器中管理状态栏样式的正确方法是设置导航控制器的导航栏barStyle @matt 给我看?提交答案? 谢谢,扩展在导航控制器中完成了工作。无需在plist中添加任何东西也无需添加导航barStyle 我的代码在哪里?我需要以某种方式明确调用它吗?我在导航控制器中嵌入了 VC,在拆分视图控制器的两个部分中,虽然我可以将导航栏样式从 .default 更改为 .black 并随意更改,但我完全无法说服状态栏进行更改它的显示以点亮 .black 导航栏上的文本。关于我可能遗漏的任何建议?【参考方案2】:

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

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

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

执行此操作的明显位置是viewWillAppear,只要此视图控制器成为导航控制器堆栈的顶部,就会调用它:

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

【讨论】:

由于这是造成误解的根源,因此一些代码示例将对我和将来遇到此问题的人有所帮助。根据我所做的研究,没有人对这个问题写出好的答案,因此我很困惑 但是当您在控制器的 viewDidLoad 或 viewDidAppear 方法中覆盖状态栏样式时,通过添加 UIApplication.shared.statusBarStyle = .default // 或 .light 状态栏会正常变化 @MhmdRizk 这似乎可行,但我正在展示 Apple 打算让您做什么。它非常差/没有记录,但我从 Apple 开发人员论坛上的 Apple 员工那里得到了这种技术。导航控制器通过根据导航栏的栏样式设置状态栏样式来自动响应。这让每个视图控制器负责状态栏样式,这是现代架构。因此,这样做比直接与应用程序对话“越过导航控制器”要好。 我还有一个问题,我们是否需要在 Info.plist 文件中添加这个基于视图控制器的状态栏外观属性,谢谢。@matt @MhmdRizk 不,这完全过时了。状态栏的视图控制器控件多年来一直是默认的。【参考方案3】:

Swift 5、iOS 12

这里的大多数答案都很有帮助,但并没有立即为我解决问题。我有一个嵌套结构(根 VC > 标签栏 VC > 导航 VC > 特定页面 VC),我希望其中一个推送页面 VC 更改状态栏颜色。

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

@kelin 的回答让我朝着正确的方向前进。 childForStatusBarStyle 有助于指定应检查哪个子 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

第 3 步:在确定状态栏外观的子 VC 中,覆盖样式:

override var preferredStatusBarStyle: UIStatusBarStyle 
  return .lightContent

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

第 5 步:当子 VC 从层次结构中移除并且您想恢复状态栏样式时,请务必再次从根 VC 调用 setNeedsStatusBarAppearanceUpdate(),可能在 @987654337 @。

作为旁注,上述解决方案不需要我将View controller-based status bar appearance Info.plist 值显式设置为YES,许多答案都参考了。

【讨论】:

【参考方案4】:

UINavigationController 有另一种解决方案。您可以将其子类化并将childForStatusBarHidden 属性与setNeedsStatusBarAppearanceUpdate() 结合使用。

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

    override var viewControllers: [UIViewController] 
        didSet  setNeedsStatusBarAppearanceUpdate() 
    

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

【讨论】:

以上是关于更新视图控制器之间的状态栏样式的主要内容,如果未能解决你的问题,请参考以下文章

状态栏样式与 ParentViewController 不同的模态视图控制器

iOS 7 及更高版本:为每个视图控制器设置状态栏样式

Swift 4 - 特定视图控制器状态栏样式不变

状态栏样式不会因单个视图而改变 - Swift 2/iOS9

无法使 SFSafariViewController 状态栏样式 lightContent

是否可以更改所有视图控制器的状态栏颜色?