Obtenir une reference à la vue / window la plus haute dans l'application iOS

Je crée un cadre réutilisable pour l'affichage des notifications dans une application iOS. Je voudrais que les vues de notification soient ajoutées au-dessus de tout le rest dans l'application, un peu comme un UIAlertView. Lorsque je lance le gestionnaire qui écoute les events NSNotification et ajoute des vues en réponse, je dois get une reference à la vue la plus haute de l'application. C'est ce que j'ai en ce moment:

_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject]; 

Cela fonctionnerait-il pour n'importe quelle application iOS ou est-ce un moyen plus sûr / meilleur d'get la vue de dessus?

Habituellement, cela vous donnera la vue de dessus, mais il n'y a aucune garantie qu'elle soit visible par l'user. Il pourrait être hors de l'écran, avoir un alpha de 0.0, ou pourrait avoir une taille de 0x0 par exemple.

Il se peut aussi que keyWindow n'ait pas de sous-vues, donc vous devriez probablement tester cela en premier. Ce serait inhabituel, mais ce n'est pas impossible.

UIWindow est une sous-class de UIView, donc si vous voulez vous assurer que votre notification est visible pour l'user, vous pouvez l'append directement à la keyWindow en utilisant addSubview: et ce sera instantanément la vue la plus haute. Je ne suis pas sûr si c'est ce que vous cherchez à faire. (En fonction de votre question, il semble que vous le sachiez déjà.)

Chaque fois que je veux afficher une superposition par-dessus tout, je l'ajoute directement au-dessus de la window d'application:

 [[[UIApplication sharedApplication] keyWindow] addSubview:someView] 

Il y a deux parties du problème: Fenêtre supérieure, vue supérieure sur la window supérieure.

Toutes les réponses existantes ont raté la partie supérieure de la window. Mais [[UIApplication sharedApplication] keyWindow] n'est pas garanti d'être la window supérieure.

  1. Fenêtre supérieure Il est très peu probable qu'il y ait deux windows avec le même coexistant windowLevel pour une application, donc nous pouvons sortinger toutes les windows par windowLevel et get le plus haut.

     UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) { return win1.windowLevel - win2.windowLevel; }] lastObject]; 
  2. Vue de dessus sur la window supérieure. Juste pour être complet. Comme déjà souligné dans la question:

     UIView *topView = [[topWindow subviews] lastObject]; 

En fait, il pourrait y avoir plus d'un UIWindow dans votre application. Par exemple, si un keyboard est à l'écran, les [[UIApplication sharedApplication] windows] contiendront au less deux windows (votre window-key et la window du keyboard).

Donc, si vous voulez que votre vue apparaisse sur les deux, alors vous devez faire quelque chose comme:

 [[[[UIApplication sharedApplication] windows] lastObject] addSubview:view]; 

(En supposant que lastObject contienne la window avec la plus haute priorité windowLevel).

Je m'en tiens à la question que le titre indique et non la discussion. Quelle vue est la plus visible sur un point donné?

 @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 

Peut être utilisé directement avec n'importe quel UIWindow comme récepteur ou n'importe quel UIView comme récepteur.

Si vous ajoutez une vue de chargement (une vue d'indicateur d'activité par exemple), assurez-vous d'avoir un object de la class UIWindow. Si vous affichez une feuille d'action juste avant d'afficher votre vue de chargement, keyWindow sera la UIActionSheet et non UIWindow . Et puisque la feuille d'action disparaîtra, la vue de chargement disparaîtra avec elle. Ou c'est ce qui me causait des problèmes.

 UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow]; if (![NSSsortingngFromClass([keyWindow class]) isEqualToSsortingng:@"UIWindow"]) { // find uiwindow in windows NSArray *windows = [UIApplication sharedApplication].windows; for (UIWindow *window in windows) { if ([NSSsortingngFromClass([window class]) isEqualToSsortingng:@"UIWindow"]) { keyWindow = window; break; } } } 

Si votre application fonctionne uniquement en orientation portrait, cela suffit:

 [[[UIApplication sharedApplication] keyWindow] addSubview:yourView] 

Et votre vue ne sera pas affichée sur le keyboard et la barre d'état.

Si vous souhaitez get une vue supérieure au-dessus du keyboard ou de la barre d'état, ou si vous souhaitez que la vue la plus haute puisse pivoter correctement avec les périphériques, essayez cette structure:

https://github.com/HarrisonXi/TopmostView

Il prend en charge iOS7 / 8/9.

essaye ça

UIWindow * window = [[[UIApplication sharedApplication] windows] lastObject];

Utilisez simplement ce code si vous voulez append une vue au-dessus de tout à l'écran.

 [[UIApplication sharedApplication].keyWindow addSubView: yourView];