不改变状态栏颜色的情况下呈现视图控制器,就像UIAlertController一样

8
在执行某些网络操作时,我会呈现一个模态视图控制器(类似于MBProgressHUD但作为视图控制器),以防止用户交互并指示进度。
视图控制器具有modalPresentationStyle = .Custom,并使用过渡委托和自定义表示控制器进行动画处理。除了动画转换之外,它们没有任何自定义操作驱动演示。
我的问题是每当呈现视图控制器时,它就会将状态栏颜色变为黑色。 我可以覆盖preferredStatusBarStyle使其始终返回.LightContent,但有时这个视图控制器是在带有.Default的视图控制器上呈现的,我也不想在那里更改它。 基本上,我想要与UIAlertController相同的行为。

Screenshot showing presented view controller causing dark status bar content

我尝试配置演示控制器,将呈现的视图控制器移出状态栏空间:
private class SEUIProgressControllerPresentationController: UIPresentationController {

    override func shouldPresentInFullscreen() -> Bool {
        return false
    }

    private override func frameOfPresentedViewInContainerView() -> CGRect {
        return super.frameOfPresentedViewInContainerView().insetBy(dx: 40, dy: 100)
    }

    ...
}

这些设置确实将呈现的控制器顶部移出了状态栏,但状态栏仍然受到影响。我是否遗漏了某个属性,可以阻止我的视图控制器更新状态栏样式?
1个回答

6

更新

看起来这个问题已经在 iOS 10 中得到解决了。默认行为是忽略呈现的视图控制器中的状态栏规则,除非呈现的视图控制器具有 modalPresentationCapturesStatusBarAppearance == true,或者您使用几个内置的呈现控制器之一,它们延伸到状态栏空间中(而不是 .custom)。

基本上,对于自定义的行为已经从强制选择变成了默认选择退出。


iOS 9.x 及更低版本

经过深入挖掘,设置应用程序状态栏颜色的内部逻辑如下:

var viewController = window.rootViewController!

while let presentedViewController = viewController.valueForKey("_presentedStatusBarViewController") as? UIViewController {
    viewController = presentedViewController
}

while let childViewController = viewController.childViewControllerForStatusBarStyle() {
    viewController = childViewController
}

let style = viewController.preferredStatusBarStyle()

视图控制器的属性_presentedStatusBarViewController在呈现过程中基于其呈现控制器的私有方法_shouldChangeStatusBarViewController()的值进行分配。该方法的默认实现是返回true,而_UIAlertControllerPresentationController和其他几个呈现控制器则返回false。
这意味着最直接的不改变状态栏的方法就是将此方法添加到我的呈现控制器中:
private class SEUIProgressControllerPresentationController: UIPresentationController {

    @objc func _shouldChangeStatusBarViewController() -> Bool {
        return false
    }

    ...
}

很遗憾,这不会通过应用商店的审核。

相反,我的做法是在我的视图控制器中重新创建应用于展示视图控制器的逻辑:

public class SEUIProgressController: UIViewController {

    ...
    public override func preferredStatusBarStyle() -> UIStatusBarStyle {

        guard var targetViewController = presentingViewController else {
            return .LightContent
        }

        while let parentViewController = targetViewController.parentViewController {
            targetViewController = parentViewController
        }

        while let childViewController = targetViewController.childViewControllerForStatusBarStyle() {
            targetViewController = childViewController
        }

        return targetViewController.preferredStatusBarStyle()
    }

    public override func prefersStatusBarHidden() -> Bool {

        guard var targetViewController = presentingViewController else {
            return false
        }

        while let parentViewController = targetViewController.parentViewController {
            targetViewController = parentViewController
        }

        while let childViewController = targetViewController.childViewControllerForStatusBarHidden() {
            targetViewController = childViewController
        }

        return targetViewController.prefersStatusBarHidden()
    }
}

是的,自iOS 10以来已经固定了,如果您正在使用浅色状态栏并且必须创建模态警报,则会出现奇怪的问题。您只需要设置:controllerToPresent.modalPresentationCapturesStatusBarAppearance = true,谢谢。 - José Miguel Galván

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接