Comment trouver supérieure-vue-contrôleur sur iOS
J'ai couru dans quelques cas où il serait agréable d'être en mesure de trouver la "plus haute" - vue-contrôleur (le responsable de l'affichage actuel), mais je n'ai pas trouvé un moyen de le faire.
Fondamentalement, le défi est ceci: étant Donné que l'on est en cours d'exécution dans une classe qui n'est pas une vue contrôleur (ou d'une vue) [et ne pas avoir l'adresse d'une active view] et n'a pas été transmis à l'adresse de la supérieure-vue-contrôleur (ou, disons, l'adresse de la manette de navigation), est-il possible de trouver ce point de vue contrôleur? (Et, si oui, comment?)
Ou, à défaut, est-il possible de trouver le premier point de vue?
- Donc, vous dites qu'il n'est pas possible.
- non, je dis qu'il semble que votre code pourrait utiliser un peu de re-conception, car il est rarement besoin de le savoir. Aussi, l'idée de "supérieur" n'est valable que dans certains contextes, et encore pas toujours.
- J'avais mal lu votre question. Il y a beaucoup de si et de mais en essayant de répondre à ça. Cela dépend de votre point de vue contrôleur de débit. @Wilbur la réponse devrait être un bon point de départ pour tracer vers le bas.
- Eh bien, nous allons simplifier à un cas spécifique. Si je voulais écrire un clone de UIAlertView, comment pourrais-je le faire? Notez qu'il peut fonctionner très bien sans être passé tout addressibility à d'autres contrôleurs et des vues.
- L'ajout d'un deuxième UIWindow fonctionne bien pour l'affichage des alertes-comme des calques.
- Ouais, UIWindow semble être la façon de faire une alerte. Ne pas résoudre les problème de déterminer le niveau supérieur-vue-contrôleur (où l'on veut placer un autre sur le dessus), mais je suppose que ceux qui ont besoin d'être traités séparément.
- Que faire si vous avez vraiment besoin dans certains cas particulier, en plus d'un UIAlertView dans un module où vous ne traiter les données? Vous ne voulez pas perdre son temps avec un contrôleur de référence dans le module de données, en prenant soin de la régler correctement dans toute l'INTERFACE utilisateur lorsque vous appelez le module de données. Ou vous faire? Et peut-être mieux est de placer un entre-deux de la couche... je pense simplement ici... vous avez peut-être droit.
Vous devez vous connecter pour publier un commentaire.
iOS 4 introduit le rootViewController bien sur UIWindow:
Vous devez définir vous-même après la création de la vue-contrôleur si.
-[UINavigationController topViewController]
). Puis il y a le mot "racine", qui est la racine de l'arbre (comme-[UIWindow rootViewController]
.UIViewController
et pasUIWindow
.Je pense que vous avez besoin d'une combinaison de la accepté de répondre et @fishstix de
Swift 3.0+
UINavigationController
et demander sontopViewController
ou même vérifier pourUITabBarController
et demanderselectedViewController
. Ainsi, vous obtenez la vue-contrôleur qui est actuellement visible à l'utilisateur.s
keyWindow.rootViewController` est toujours_UIModalItemsPresentingViewController
pour moi (iOS 7). Cependant, lorsque j'utilise, leappDelegate.window
propriété, elle renvoie le contrôleur que je voulais.presentingViewController
, parce que certains contrôleurs peuvent set ` definesPresentationContext` OUIPour compléter JonasG de réponse (qui à gauche en sortant de l'onglet de la barre de contrôleurs en traversant), voici ma version de retour actuellement visible-vue-contrôleur:
childViewControllers
Un complet non-récursive version, en prenant soin de scénarios différents:
UINavigationController
UITabBarController
Objective-C
Swift 4+
visibleViewController
pour le rendre clair ce qu'il fait.Tirer le maximum de plus-vue-contrôleur pour Swift à l'aide des extensions de
Code:
Utilisation:
Pour compléter Eric réponse (qui a laissé de côté popovers, les contrôleurs de la navigation, tabbarcontrollers, vue contrôleurs ajouté que les sous-vues de certains autres contrôleurs de vue en traversant), voici ma version de retour actuellement visible-vue-contrôleur:
=====================================================================
=====================================================================
Et maintenant tout ce que vous devez faire pour obtenir la meilleure plus-vue-contrôleur est d'appeler la méthode ci-dessus comme suit:
Cette réponse comprend
childViewControllers
et maintient un environnement propre et lisible de la mise en œuvre.J'ai reçu récemment cette situation dans mon projet, qui a tenu à afficher une notification de vue quel que soit le contrôleur affiche était et quel était le type (UINavigationController, manette classique ou personnalisé-vue-contrôleur), lorsque l'état du réseau a changé.
Donc j'ai juste sorti mon code, ce qui est assez facile et en fait basé sur un protocole, de sorte qu'il est flexible avec chaque type de conteneur contrôleur.
Il semble être lié avec les dernières réponses, mais dans beaucoup de souplesse.
Vous pouvez saisir le code ici : PPTopMostController
Et a obtenu le plus haut du contrôleur à l'aide de
C'est une amélioration à Eric réponse:
_topMostController(UIViewController *cont)
est une fonction d'assistance.Maintenant, tout ce que vous devez faire est d'appeler
topMostController()
et le plus haut UIViewController devrait être de retour!self
doit appartenir.Simple extension pour
UIApplication
dans Swift:REMARQUE:
Il se soucie
moreNavigationController
dansUITabBarController
Simple d'utilisation:
Ici est mon point de vue sur ce. Grâce à @Stakenborg pour désigner la façon de sauter arriver UIAlertView comme le plus haut contrôleur de
getSomething:
en Objective-C. Cela a une signification particulière (plus: cocoadevcentral.com/articles/000082.php) et vous n'avez pas satisfaire à ces exigences dans votre code.Pour la dernière version de Swift Version:
Créer un fichier, le nom
UIWindowExtension.swift
et collez le bout de code suivant:L'utiliser n'importe où comme:
switch
au lieu de if else. 3. pas sûr que vous besoin d'une fonction statique ainsi, je pense que vous pouvez le faire facilement en première instance var que vous avez déclaré. 4. Probablement préférable de ne pas créer trop de fonctions globales, mais c'est une question de goût. Vous pouvez utiliser une ligne de code pour réaliser la fonction globale de l'effet:UIApplication.sharedApplication().delegate?.window?.visibleViewController
Utiliser en dessous de l'extension de saisir visible en cours
UIViewController
. Travaillé pour Swift 4.0 et versions ultérieuresSwift 4.0 et versions Ultérieures:
Comment l'utiliser?
Voici ce qui a fonctionné pour moi.
J'ai trouvé que, parfois, le contrôleur a été nulle sur la touche de la fenêtre, comme le keyWindow est certains OS de chose, comme une alerte, etc.
Expansion sur @Eric réponse, vous devez être attentif à ce que les keyWindow est en fait la fenêtre que vous souhaitez. Si vous essayez d'utiliser cette méthode après avoir appuyé sur quelque chose dans un affichage des alertes par exemple, la keyWindow sera effectivement l'alerte de la fenêtre, et qui va causer des problèmes pour vous sans aucun doute. Ce qui m'est arrivé dans la nature lors de la manipulation des liens par l'intermédiaire d'une alerte et a causé SIGABRTs avec AUCUNE TRACE de la PILE. Total chienne à déboguer.
Voici le code que j'utilise maintenant:
Hésitez pas à mélanger cela avec toute la saveur de la récupération de la vue de dessus contrôleur de vous comme de l'autre des réponses sur cette question.
Alternative solution Swift:
Encore une autre solution Swift
Cette solution est la plus complète. Il prend en considération:
UINavigationController
UIPageViewController
UITabBarController
Et le premier présenté-vue-contrôleur de la vue de dessus contrôleur
L'exemple est dans Swift 3.
Il y a 3 surcharges
Swift 4.2 Extension
L'utiliser à partir de n'importe où, comme,
ou comme,
Adapter à toutes les classes comme UINavigationController, UITabBarController
Profitez-en!
Excellente solution rapide, de mettre en œuvre dans AppDelegate
Je pense que la plupart des réponses ont complètement ignoré
UINavigationViewController
, donc j'ai géré ce cas d'utilisation avec la suite de la mise en œuvre.Un concise mais complète solution rapide 4.2, prend en compte UINavigationControllers, UITabBarControllers, présenté et enfant vue contrôleurs:
Utilisation:
Ne sais pas si cela va aider à ce que vous essayez d'accomplir en trouvant le premier-vue-contrôleur, mais j'ai essayé de présenter un nouveau point de vue contrôleur, mais si ma vue racine contrôleur déjà eu une boîte de dialogue modale, il serait bloqué, donc je serais cycle vers le haut de tous les modal vue contrôleurs à l'aide de ce code:
Swift:
Utilisation:
Ci-dessous deux fonction peut vous aider à trouver les topViewController sur la Pile de vue des contrôleurs. Vous pouvez avoir besoin de personnalisation plus tard, mais pour que ce code est génial pour comprendre le concept de topViewController ou la pile de viewControllers.
Vous pouvez utiliser [viewController Classe] méthode pour trouver le type de classe d'un viewController.
Et une autre solution Swift
Beaucoup de ces réponses sont incomplètes. Bien que ce soit en Objective-C, c'est la meilleure compilation de tous ceux que j'ai pu mettre ensemble pour l'instant, en tant que non-récursive bloc:
Lien vers Gist, en cas de révision: https://gist.github.com/benguild/0d149bb3caaabea2dac3d2dca58c0816
Code fins de référence et de comparaison:
Si la racine controller est une manette de navigation, de façon correcte à trouver les meilleurs visible contrôleur est:
Voici un extrait de UINavigationController.h:
Cela fonctionne très bien pour trouver le haut viewController Un de toutes les racines de vue controlle
vous pourrez trouver le haut-vue-contrôleur en utilisant
self
n'a pas denavigationController
de la propriété.Une autre solution repose sur le répondeur de la chaîne, qui peut ou peut ne pas fonctionner en fonction de ce que le premier intervenant est:
Exemple de pseudo-code:
Pour éviter un lot de complexité-je garder la trace du viewController par la création d'un viewController délégué et définir pour soi à l'intérieur de chaque méthode viewDidLoad, de cette façon quand vous chargez un nouveau point de vue le ViewController tenu à le délégué correspondent à ce point de vue est viewController. Cela peut être moche, mais ça fonctionne à merveille, et theres aucun besoin d'avoir une manette de navigation ou de tout ce non-sens.
Réponse précédente ne semble pas gérer les cas où rootController sont UITabBarController ou UINavigationController.
Ici est la fonction de swift qui travaille pour ces cas :
Je pense que la solution de Rajesh est presque parfait, mais je pense que c'est mieux traverser les sous-vues de haut en bas, j'ai changé à la suite:
Ici est une Swift de la mise en œuvre d'une application avec UINavigationController est comme une racine.
Je pense que peut-être une chose qui est négligé ici. C'est peut-être mieux de passer le parent viewController dans la fonction qui est à l'aide de la viewController. Si vous êtes à la pêche autour de l'avis de la hiérarchie pour trouver le top view controller que c'est probablement la violation de la séparation de la couche du Modèle et de la couche d'INTERFACE utilisateur et est une odeur de code. Juste le signaler, j'ai fait de même, alors rendu compte qu'il était beaucoup plus simple de juste passer à la fonction, en ayant le modèle de l'opération retour à la couche d'INTERFACE utilisateur où j'ai une référence à la vue du contrôleur.
Ma question était un peu différente, je l'aide SWRevealViewController dans mon application.
J'ai utilisé Yuchen Zhong est réponse mais il y a toujours le retour topViewController comme SWRevealViewController. Pour ceux qui sont à l'aide de SWRevealViewController ou une autre gousse de développer sideMenu. Voici mon extension à Yuchen Zhong réponse:
Vous devez utiliser:
Quand il y a un uiactionsheet sur
[UIApplication sharedApplication].keyWindow
, il n'est pas en droit d'utiliser keyWindow comme mentionné dans cette réponse.