获取对iOS应用程序中最顶层视图/窗口的引用
我正在创build一个在iOS应用程序中显示通知的可重用框架。 我希望将通知视图添加到应用程序中的所有其他应用程序的顶部,有点像UIAlertView。 当我启动监听NSNotification事件并添加视图的pipe理器时,我需要获取应用程序中最顶层视图的引用。 这是我现在所拥有的:
_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
这将工作对于任何iOS应用程序,或者是他们更安全/更好的方式来获得顶视图?
通常这会给你顶视图,但不能保证它是用户可见的。 它可能不在屏幕上,具有0.0的alpha,或者可以具有例如0x0的大小。
也可能是keyWindow没有子视图,所以你应该先testing一下。 这将是不寻常的,但这不是不可能的。
UIWindow是UIView的一个子类,所以如果你想确保你的通知对用户是可见的,你可以使用addSubview:
把它直接添加到keyWindow中addSubview:
它将立即成为最顶层的视图。 我不确定这是不是你想要做的。 (基于你的问题,看起来你已经知道这一点。)
无论何时我想在其他任何地方显示一些覆盖图,我只是直接将它添加到应用程序窗口的顶部:
[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
问题有两个部分:顶窗,顶窗顶视图。
所有现有的答案都错过了顶窗部分。 但[[UIApplication sharedApplication] keyWindow]
不能保证是顶层窗口。
-
顶部窗户。 这是不太可能的,将有两个窗口具有相同的
windowLevel
共存为一个应用程序,所以我们可以通过windowLevel
sorting所有的窗口,并获得最高的一个。UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) { return win1.windowLevel - win2.windowLevel; }] lastObject];
-
顶视图上的顶视图。 只是要完成。 正如在问题中已经指出的那样:
UIView *topView = [[topWindow subviews] lastObject];
实际上在应用程序中可能会有多个UIWindow。 例如,如果屏幕上出现键盘,则[[UIApplication sharedApplication] windows]
将至less包含两个窗口(您的键盘窗口和键盘窗口)。
所以如果你想让你的观点出现在他们两个的顶部,那么你必须做一些事情:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];
(假设lastObject包含具有最高windowLevel优先级的窗口)。
我坚持的问题是标题状态而不是讨论。 哪个视图在任何给定的点上都可以看到?
@implementation UIView (Extra) - (UIView *)findTopMostViewForPoint:(CGPoint)point { for(int i = self.subviews.count - 1; i >= 0; i--) { UIView *subview = [self.subviews objectAtIndex:i]; if(!subview.hidden && CGRectContainsPoint(subview.frame, point)) { CGPoint pointConverted = [self convertPoint:point toView:subview]; return [subview findTopMostViewForPoint:pointConverted]; } } return self; } - (UIWindow *)topmostWindow { UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) { return win1.windowLevel - win2.windowLevel; }] lastObject]; return topWindow; } @end
可以直接使用任何UIWindow作为接收器或任何UIView作为接收器。
如果您要添加一个加载视图(例如一个活动指示器视图),请确保您有一个UIWindow类的对象。 如果在显示加载视图之前显示一个操作表,那么keyWindow
将是UIActionSheet
而不是UIWindow
。 而且由于动作表将消失,装载视图将随之消失。 或者这就是导致我的问题。
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow]; if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) { // find uiwindow in windows NSArray *windows = [UIApplication sharedApplication].windows; for (UIWindow *window in windows) { if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) { keyWindow = window; break; } } }
如果您的应用程序只能以纵向方式工作,这就足够了:
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]
而且你的视图不会显示在键盘和状态栏上。
如果你想通过键盘或者状态栏获得最上面的视图,或者你想让最上面的视图可以正确地使用设备旋转,请尝试这个框架:
https://github.com/HarrisonXi/TopmostView
它支持iOS7 / 8/9。
尝试这个
UIWindow * window = [[[UIApplication sharedApplication] windows] lastObject];
只要使用这个代码,如果你想在屏幕上的所有东西上面添加一个视图。
[[UIApplication sharedApplication].keyWindow addSubView: yourView];