web-dev-qa-db-fra.com

Obtenir une référence à la vue/fenêtre la plus en haut dans l'application iOS

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?

95
typeoneerror

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à.)

36
Kris Markel

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]
108
samvermette

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.

  1. 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];
    
  2. 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];
    
45
an0

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).

11
lorean

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.

3
hfossli

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.

1
Harrison Xi

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;
        }
    }
}
1
Miha Hribar

essaye ça

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

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