覆盖基于视图控制器的状态栏外观

时间:2017-03-19 15:00:04

标签: ios uiviewcontroller ios8 uistatusbar

我有一个基于视图控制器的状态栏外观设置为YES的应用。我的一些观点很暗,我的一些观点有轻量级内容,而且应用程序有一个非常复杂的视图控制器层次结构,但它完全适用于子类化和覆盖适当的方法以及捕获演示样式等的模态视图。)

但是,我需要一种全局方式来查看顶部的特定项目(在状态栏后面,在我的应用范围内),就像个人热点/ GarageBand录制/通话等条形栏一样在顶部。由于条形图的背景颜色,我想在显示条形图时覆盖状态栏外观(可以在应用程序的任何位置显示,因此我将UIWindow子类化并将其显示代码和视图直接放在那里) 。条形图显示我想要的屏幕上有轻量内容状态栏(因为我的酒吧的文字是白色,背景是黑暗的)但在黑暗内容状态栏上看起来很糟糕(不,我无法改变酒吧的颜色。)

如何覆盖"无论当前呈现的视图控制器是全局的首选状态栏样式(当然,不遍历所有视图控制器中状态栏方法的所有实例) ,同时仍然使用基于视图控制器的状态栏外观?我的应用程序面向iOS 8.0 +。

1 个答案:

答案 0 :(得分:0)

我最终以一种非常hacky(但工作)的方式结束了。它可能在每种情况下都不起作用,但它在我的工作中起作用。我保持了视图原样,并没有触及单个视图或控制器。

首先,我目前正在显示最顶层的视图控制器。我使用了iPhone -- How to find topmost view controller中的代码并对其进行了一些修改以处理导航控制器和标签栏控制器案例:

+ (UIViewController*) topmostControllerForViewController:(__kindof UIViewController*)topController
{
    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }
    if([topController isKindOfClass:[UINavigationController class]]){
        UINavigationController *navController = topController;
        return [self topmostControllerForViewController:navController.visibleViewController];
    }
    if([topController isKindOfClass:[UITabBarController class]]){
        UITabBarController *tabController = topController;
        return [self topmostControllerForViewController:tabController.selectedViewController];
    }
    return topController;
}

+ (UIViewController*) topmostController
{
    __kindof UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    return [self topmostControllerForViewController:topController];
}

然后我创建了一个没有视图的视图控制器(viewnil)。在它的init方法中(在第一次调用中工作,如果放入viewDidLoad:,因为它在转换过程中被调用,而且为时已晚),我添加了以下内容:

self.modalPresentationCapturesStatusBarAppearance = YES;
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;

该代码允许我的“虚拟”视图(较少)控制器处理所有演示文稿上下文,包括状态栏应用程序以及其他视图控制器出现时会发生什么。在当前上下文中显示时,后面的视图控制器不会从视图层次结构中删除。如果我不这样做,它将被删除,屏幕将是黑色的(因为我没有任何视图,我希望显示以前的视图控制器。)

到目前为止一切顺利。然后,我正常显示我的栏,但同时,在没有任何视图的情况下以模态方式呈现该视图控制器。因为视图控制器没有任何视图并且在当前上下文中呈现,所以它在视觉上没有以任何方式出现,但由于它是模态演示并且虚拟视图控制器被设置为捕获演示样式,因此它触发了iOS向我的应用询问状态栏样式。我只是在视图控制器方法中设置了我想要的状态栏样式。

有一点问题。当我展示新的视图控制器时,系统在我之前的视图控制器上添加了UITransitionView。如果存在实际视图,则它将位于转换视图的顶部。转换视图是完全透明的,但它启用了用户交互并捕获了所有触摸事件,使我的应用程序无响应,直到我解除了控制器。我需要我以前的视图控制器来接收触摸事件。我已经深入挖掘并找到模态演示文稿添加过渡视图的位置,并在过渡动画完成后呈现视图控制器时将其删除:

for (UIView *view in self.subviews) {
        NSString *className = NSStringFromClass([view class]);
        if([className hasPrefix:@"UIT"] && className.length == 16){
            //this must be UITransitionView, but I'm not using it directly since it may interfere with private API usage and get app rejected by Apple.
            //now, we need to find another transition view inside this and remove it
            for (UIView *innerView in view.subviews) {
                className = NSStringFromClass([innerView class]);
                if([className hasPrefix:@"UIT"] && className.length == 16){
                    //this is the transition view that we need to remove
                    [innerView removeFromSuperview];
                } 
            }
        }
}

由于UITransitionView是私有视图类型,我不确定它是否会导致App Store出现问题,因此我通过检查第一个字母{{1}对UITransitionView进行了启发式检查。并检查类名的长度。它不是防弹的,但似乎有效并且不太可能返回误报。

现在一切都按预期工作了。这很糟糕,将来可能会破裂,特别是如果模式演示在幕后发生变化。但请放心,它有效。