web-dev-qa-db-fra.com

Comment identifier qu'un UIViewController est présenté

J'ai créé une sous-classe UIViewController qui peut soit être insérée dans une pile de navigation d'un UINavigationController, soit présentée (modalement) à partir de n'importe quel UIViewController. Je dois identifier si mon contrôleur de vue est présenté. S'il est présenté, je dois ajouter une barre d'outils avec un bouton de fermeture en haut du contrôleur de vue. (sinon, s'il est inséré dans la pile de navigation, le bouton de fermeture par défaut sera ajouté, en utilisant le fait que l'utilisateur peut revenir en arrière)

Dans toutes les versions disponibles, dites 4.3, 5.0, jusqu'à 6.0, de l'intérieur d'une sous-classe UIViewController, puis-je supposer que le contrôleur de vue est présenté (modalement) si la condition suivante est remplie?.

if(self.parentViewController == nil || self.navigationController == nil)
25
saikamesh

Avec iOS 5, UIViewController a obtenu une propriété en lecture seule nommée presentingViewController, qui remplace l'ancienne sémantique de parentViewController (qui décrit maintenant confinement). Cette propriété peut être utilisée lorsqu'un contrôleur de vue doit accéder au contrôleur de vue qui le présente. Remarque: il s'agira souvent d'autre chose que ce à quoi vous vous attendiez, si vous êtes nouveau dans l'API!

De plus, la propriété isBeingPresented a été introduite pour résoudre de façon assez précise la classe de situations dans laquelle vous vous trouvez. Recherchez cette propriété dans le viewWillAppear: de votre contrôleur de vue.

Mettre à jour

Je suppose que vous semblez également cibler iOS 4.3:
Dans ce cas, vous devez protéger l'appel de isBeingPresented avec une if ([self respondsToSelector:…]). Vous pouvez ensuite, dans le bloc else, vérifier si le parentViewController n'est pas nul.

Une autre approche de la compatibilité ascendante pourrait consister à remplacer +resolveInstanceMethod: pour ajouter une implémentation pour -isBeingPresented au moment de l'exécution. Cela laissera vos sites d’appel propres, et vous vous débarrasserez de la magie du runtime dès que vous abandonnerez l’ancien support iOS ;-)

Notez cependant qu'il existe des cas Edge et que vous vous approchez également lorsque vous utilisez iOS <5:

Le contrôleur de vue peut être présenté comme n'importe quel autre contrôleur de vue, y compris les contrôleurs de navigation. Lorsque ce dernier cas se produit, vous n’avez plus de chance: parentViewController sera nil, tandis que navigationController sera pas . Vous pouvez essayer d’ajouter du code peu maniable afin d’atténuer cette limitation dans les anciennes versions de l’iOS… ou vous pouvez simplement le laisser tomber.

31
danyowdee

J'utilise ce code pour vérifier si UIViewController est présenté.

if (uiviewcontroller.presentingViewController != nil) {
   // do something
}
10
Evelyn Loo

Pour gérer ce type de comportement, je règle/réinitialise généralement un BOOL en le basculant dans les méthodes viewWillAppear/viewWillDisappear.

En passant, vos conditions de test semblent incorrectes. Je pense que vous devriez utiliser

if(self.parentViewController != nil || self.navigationController != nil)

Pourquoi ne pouvez-vous pas toujours ajouter la barre d'outils à votre contrôleur de vue? Existe-t-il des cas où la vue est chargée mais jamais présentée?

7
Gl0ub1l

J'avais un cas similaire, mais le contrôleur de vue que j'ai présenté est intégré dans son propre contrôleur de navigation . Donc, dans ce contrôleur de vue lorsque je dois déterminer s'il faut ou non ajouter le bouton de fermeture par rapport à un bouton de retour, je vérifie simplement la taille de la pile des contrôleurs de navigation . Si l'écran est présenté, la taille de la pile doit être égale à un (bouton de fermeture requis) ... et si elle est poussée à l'aide d'un contrôleur de navigation existant, la taille de la pile sera supérieure à un (bouton de retour nécessaire).

BOOL presented = [[self.navigationController viewControllers] count] == 1;
7
Martin M Reed

@saikamesh.

Lorsque vous utilisez UINavigationController pour naviguer dans votre viewControllers, je pense que vous pouvez utiliser topViewController ( Doc here ) et visibleViewController ( Doc à nouveau ) pour atteindre votre intention.

Vous mentionnez que:

lorsqu'il est enfoncé dans la pile de navigation, le bouton de fermeture par défaut sera ajouté, en utilisant que l'utilisateur peut revenir en arrière

Si l'instance du UIViewController spécifique est importante, je pense qu'il est préférable de créer une instance singleton partagée et de fournir un indicateur global présenté:

id specificVC = [SpecificViewController sharedInstance];
if (specificVC.isPushed) {
    [self.navController popToViewController:specificVC animated:YES];
}

et pour vérifier s'il est présenté:

if ([self.navController.visibleViewController isKindOfClass:[SpecificViewController class]]) {
    // Hide or add close button
    self.isPresented = YES;
}

Ou, vous pouvez lire la réponse bien acceptée .

:) L'espoir aide.

3
Jason Lee

Vous pouvez le faire comme ça, c'est rapide et sûr 

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

// Find the top controller on the view hierarchy
while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}

// If the top controller it is not already presented
if (![topController isKindOfClass:[YourViewController class]]) {
    // Present it
    [topController presentViewController:yourViewController animated:YES completion:nil];
}
else {
// do some stuff here
}
2
Alejandro Luengo

S'il vous plaît vérifier de cette façon:

 for (UIViewController*vc in [self.navigationController viewControllers]) {
    if ([vc isKindOfClass: [OffersViewController class]]){ //this line also checks OffersViewController is presented or not 

        if(vc.isViewLoaded){
             NSLog(@"Yes");
        }

    }
}
2
Banker Mittal

Une réponse élégante que je n'ai pas vue ici:

// Edit: Added 2 other modal cases
extension UIViewController {
    var isModal: Bool { 
        return self.presentingViewController?.presentedViewController == self
            || (navigationController != nil && navigationController?.presentingViewController?.presentedViewController == navigationController)
            || tabBarController?.presentingViewController is UITabBarController
    }
}

crédit: basé sur this Gist

1
AmitaiB

Vous pouvez à tout moment vérifier si un contrôleur de vue modale est présenté ou non à l'aide de la propriété modalViewController de votre contrôleur de navigation. Ex:

   UIViewController *presentedController = self.navigationController.modalViewController;
   if (presentedController) {
      // At this point, you have a view controller presented from your navigation controller
      if ([presentedController isKindOfClass:[controllerYouWantToCheck class]]) {
         // add your toolbar/buttons/etc here
      }
   }
1
Vlad

Si c'était moi, j'aurais une méthode d'init personnalisée et l'utiliserais lors de la création du vc.

vc = [[[MyUIViewControllerSubClass alloc] init] initWithToolbarAndCloseButton:YES];
0
ader

Petite modification dans la réponse de @AmitaiB pour créer une fonction, 

func isModallyPresented(tmpVC:UIViewController) -> Bool {
        return tmpVC.presentingViewController?.presentedViewController == tmpVC
            || (tmpVC.navigationController != nil && tmpVC.navigationController?.presentingViewController?.presentedViewController == tmpVC.navigationController)
            || tmpVC.tabBarController?.presentingViewController is UITabBarController
    }

Il suffit de vérifier en appelant:

if(isModallyPresented(tmpVC:myTopVC)){
//return true if viewcontroller is presented 
}
0
HDdeveloper