Je crée un framework réutilisable pour l'affichage des notifications dans une application iOS. J'aimerais que les vues de notification soient ajoutées au-dessus de tout le reste de l'application, un peu comme un UIAlertView. Lorsque je lance le gestionnaire qui écoute les événements NSNotification et ajoute des vues en réponse, je dois obtenir une référence à la vue la plus haute de l'application. Voici ce que j'ai pour le moment:
_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
Cela fonctionnerait-il pour n'importe quelle application iOS ou leur serait-il un moyen plus sûr/meilleur d'obtenir la vue de dessus?
Habituellement, cela vous donnera une vue de dessus, mais rien ne garantit que cela sera visible pour l'utilisateur. Cela peut être hors de l’écran, avoir un alpha de 0,0, ou peut-être une taille de 0x0 par exemple.
Il se peut également que keyWindow ne comporte pas de sous-vues. Vous devriez donc probablement le tester en premier. Ce serait inhabituel, mais ce n'est pas impossible.
UIWindow est une sous-classe d'UIView. Par conséquent, si vous souhaitez vous assurer que votre notification est visible par l'utilisateur, vous pouvez l'ajouter directement à la fenêtre keyWindow à l'aide de addSubview:
. Je ne sais pas si c'est ce que vous cherchez à faire. (D'après votre question, il semble que vous le sachiez déjà.)
Chaque fois que je veux afficher une superposition par-dessus tout le reste, je l'ajoute simplement par-dessus la fenêtre de l'application:
[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
Le problème comporte deux parties: la fenêtre supérieure, la vue supérieure de la fenêtre supérieure.
Toutes les réponses existantes ont manqué la partie supérieure de la fenêtre. Mais il n’est pas certain que [[UIApplication sharedApplication] keyWindow]
soit la fenêtre du haut.
Fenêtre du haut. Il est très peu probable que deux fenêtres avec la même windowLevel
coexistent pour une application. Nous pouvons donc trier toutes les fenêtres par windowLevel
et obtenir la plus haute.
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
Vue de dessus sur la fenêtre du haut. Juste pour être complet. Comme déjà indiqué dans la question:
UIView *topView = [[topWindow subviews] lastObject];
En réalité, votre application pourrait contenir plus d’une UIWindow. Par exemple, si un clavier est à l'écran, [[UIApplication sharedApplication] windows]
contiendra au moins deux fenêtres (la fenêtre du clavier et la fenêtre du clavier).
Donc, si vous voulez que votre vue apparaisse au sommet de chacune d'elles, vous devez faire quelque chose comme:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];
(En supposant que lastObject contienne la fenêtre ayant la priorité windowLevel la plus élevée).
Je m'en tiens à la question car le titre l'indique et non la discussion. Quelle vue est visible en haut 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 en tant que récepteur ou tout UIView en tant que récepteur.
Si votre application ne fonctionne qu'en orientation portrait, cela suffit:
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]
Et votre vue ne sera pas affichée sur le clavier et la barre d'état.
Si vous souhaitez obtenir une vue supérieure sur le clavier ou la barre d'état, ou si vous souhaitez que la vue la plus haute puisse pivoter correctement avec les périphériques, veuillez essayer le cadre suivant:
https://github.com/HarrisonXi/TopmostView
Il supporte iOS7/8/9.
Si vous ajoutez une vue de chargement (une vue d'indicateur d'activité, par exemple), assurez-vous de disposer d'un objet de classe UIWindow. Si vous affichez une feuille d'action juste avant d'afficher votre vue de chargement, la keyWindow
sera la UIActionSheet
et non pas la 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 (![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;
}
}
}
essaye ça
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
Utilisez simplement ce code si vous souhaitez ajouter une vue au-dessus de tout ce qui se trouve à l'écran.
[[UIApplication sharedApplication].keyWindow addSubView: yourView];