【问题标题】:Stop overlay UIWindow from controlling the status bar停止覆盖 UIWindow 控制状态栏
【发布时间】:2026-02-09 08:30:01
【问题描述】:

我正在主窗口顶部创建一个临时 UIWindow,以显示一些覆盖在我的应用程序其余部分上的少量数据。此信息不应以任何方式影响状态栏。请注意,覆盖窗口可以从非视图控制器上下文启动,这意味着位于主窗口堆栈顶部的当前视图控制器可能不知道覆盖窗口的存在。

不幸的是,一旦我执行overlayWindow.isHidden = false,它就会将状态栏的控制(其样式以及是否隐藏)转移到我的覆盖窗口的根视图控制器,我不知道如何停止它.

或者,我可以只“记住”状态栏的先前状态并让我的覆盖根视图控制器输出这些状态,但似乎没有一个好的方法来找出当前状态和状态的可见性iOS 13 中的 bar,至少它考虑到了使用新工作表效果的模态呈现视图控制器。

我怎样才能让我的覆盖 UIWindow 可靠地不影响状态栏?


编辑:我准备了一个小测试用例:https://github.com/Aquilosion/TestWindowView

测试用例显示了一个视图控制器,它每秒都会更改其状态栏外观。您可以在模式中再次打开相同的视图控制器,尽管它也请求更改状态栏,但 iOS 正确地将状态栏锁定为白色,因为视图控制器在工作表模式下永远不会到达它。当前打开窗口叠加层始终显示黑色状态栏,无论是否存在模式。我尝试将状态栏子项设置为主窗口的根视图控制器的状态栏子项。理想情况下,iOS 会尊重这一点,并在覆盖窗口可见时继续更改状态栏样式。

【问题讨论】:

  • 您找到解决方案了吗?遇到完全相同的事情。
  • 不是真的,但我认为对于许多用例,您可以创建某种“分层视图控制器”作为窗口的根视图控制器,它本身可以有各种子视图控制器,另外还可以配置它的哪个子视图控制器可以控制状态栏(与视图控制器的顺序不同)。

标签: ios swift uiwindow


【解决方案1】:

您可以覆盖覆盖窗口的根视图控制器的属性childForStatusBarStyle

class YourRootController { // root of the overlay window

    var controllerToInheritStatusAttributesFrom: UIViewController?

    override var childForStatusBarStyle: UIViewController? {
        return controllerToInheritStatusAttributesFrom
    }

}


// Call this from any place of the app, where you show the overlay window
if let controller = overlayWindow.rootViewController as? YourViewController {
    controller.controllerToInheritStatusAttributesFrom = // needed controller, which lies underneath
    controller.setNeedsStatusBarAppearanceUpdate()
}

考虑到控制器将位于不同的窗口中,我不确定它是否会有所帮助,但值得一试。

我已经完成了您的案例,只需更新代码:

private func updateStyle() {
    styleIndex += 1

    setNeedsStatusBarAppearanceUpdate()
    overlayWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
}

将此添加到 MainViewController:

required init?(coder: NSCoder) {
     super.init(coder: coder)

     modalPresentationCapturesStatusBarAppearance = true
 }

override var preferredStatusBarStyle: UIStatusBarStyle {
        if self.presentingViewController != nil {
            return .lightContent
        }
        return Self.styles[styleIndex % Self.styles.count]
    }

【讨论】:

  • 不幸的是,我认为它不起作用,要么是因为您不允许指定不是孩子的视图控制器,要么是因为它无法检测到现有的 iOS 13 表单样式状态栏变为白色的模式,即使所有视图控制器都想要黑色状态栏。
  • @Robert,你试过设置rootViewControllerForOverlayWindow.modalPresentationStyle = .overFullScreen 吗?
  • 我认为这也行不通。我准备了一个小测试用例,并用它更新了我的问题。 MainViewController.showOverlayWindow 负责显示覆盖窗口。
  • @Robert 我更新了我的答案。现在它适用于 .overFullScreen 案例
  • 您忘记在新控制器上调用 setNeedsStatusBarAppearanceUpdate。