获取对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]不能保证是顶层窗口。

  1. 顶部窗户。 这是不太可能的,将有两个窗口具有相同的windowLevel共存为一个应用程序,所以我们可以通过windowLevelsorting所有的窗口,并获得最高的一个。

     UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) { return win1.windowLevel - win2.windowLevel; }] lastObject]; 
  2. 顶视图上的顶视图。 只是要完成。 正如在问题中已经指出的那样:

     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];