我以一种非常老套(但有效)的方式结束了。它可能并不适用于所有场景,但它适用于我的场景。我保持视图原样,没有触及任何视图或控制器。
首先,我得到了当前显示的最顶层视图控制器。我使用了来自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];
}
然后我创建了一个没有视图的视图控制器(view 是 nil)。在它的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 出现问题,因此我通过检查第一个字母 UIT 并检查长度对 UITransitionView 进行了启发式检查的类名。它不是万无一失的,但它似乎有效并且不太可能返回误报。
现在一切都按预期工作。它很hacky,并且将来可能会中断,特别是如果模态表示在引擎盖下发生变化。但请放心,它有效。