在不改变状态栏颜色的情况下呈现视图控制器,如UIAlertController

Bri*_*kel 7 ios uistatusbar presentviewcontroller swift uipresentationcontroller

在执行某些网络操作时,我提供了一个模态视图控制器(类似于MBProgressHUD但作为视图控制器)以防止用户交互并指示进度.

视图控制器modalPresentationStyle = .Custom使用转换委托和自定义演示控制器进行动画处理.除了动画转换动画之外,它们没有自定义动作来驱动演示文稿.

我遇到的问题是,无论何时出现视图控制器,它都会将状态栏颜色变为黑色.我可以覆盖preferredStatusBarStyle以使其始终返回.LightContent但有时这个视图控制器呈现在视图控制器上.Default,我也不想在那里更改它.基本上,我想要有相同的行为UIAlertController.

屏幕截图显示呈现的视图控制器导致黑暗状态栏内

我已尝试配置演示控制器以将呈现的视图控制器移出状态栏空间:

private class SEUIProgressControllerPresentationController: UIPresentationController {

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

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

这些设置会将显示控制器的顶部移出状态栏,但状态栏仍会受到影响.是否有我失踪的属性会阻止我的视图控制器更新状态栏样式?

Bri*_*kel 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()
Run Code Online (Sandbox Code Playgroud)

视图控制器的属性_presentedStatusBarViewController在演示期间根据其表示控制器的私有方法的值进行分配_shouldChangeStatusBarViewController().此方法的默认实现是返回true,其中_UIAlertControllerPresentationController一些其他表示控制器返回false.

这意味着不更改状态栏的最直接方法就是将此方法添加到我的演示控制器:

private class SEUIProgressControllerPresentationController: UIPresentationController {

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不会通过App Store审核.

相反,我正在做的是重新创建将应用于视图控制器中的呈现视图控制器的逻辑:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)