J'ai lu de nombreux articles sur des personnes ayant des problèmes viewWillAppear
lorsque vous ne créez pas simplement votre hiérarchie de vues à droite. Mon problème est que je n'arrive pas à comprendre ce que cela signifie.
Si je crée un RootViewController
et appelle addSubView
sur ce contrôleur, je m'attendrais à ce que la ou les vues ajoutées soient câblées pour les viewWillAppear
événements.
Quelqu'un a-t-il un exemple de hiérarchie de vues programmatique complexe qui reçoit avec succès les viewWillAppear
événements à tous les niveaux?
État des documents d'Apple:
Avertissement: Si la vue appartenant à un contrôleur de vue est ajoutée directement à une hiérarchie de vues, le contrôleur de vue ne recevra pas ce message. Si vous insérez ou ajoutez une vue à la hiérarchie de vues et qu'elle possède un contrôleur de vue, vous devez envoyer ce message directement au contrôleur de vue associé. Si vous ne transmettez pas ce message au contrôleur de vue, toute animation associée ne sera pas affichée.
Le problème est qu'ils ne décrivent pas comment procéder. Que signifie «directement»? Comment ajouter "indirectement" une vue?
Je suis assez nouveau sur Cocoa et iPhone, donc ce serait bien s'il y avait des exemples utiles d'Apple en plus de la merde de base Hello World.
la source
Réponses:
Si vous utilisez un contrôleur de navigation et définissez son délégué, les méthodes view {Will, Did} {Appear, Disappear} ne sont pas appelées.
Vous devez utiliser les méthodes de délégué du contrôleur de navigation à la place:
la source
J'ai rencontré ce même problème. Envoyez simplement un
viewWillAppear
message à votre contrôleur de vue avant de l'ajouter en tant que sous-vue. (Il existe un paramètre BOOL qui indique au contrôleur de vue s'il est en cours d'animation pour apparaître ou non.)Regardez RootViewController.m dans l'exemple Metronome.
(En fait, j'ai trouvé les projets d'exemple d'Apple excellents. Il y a BEAUCOUP plus que HelloWorld;)
la source
[scrollView addSubview:controller.view];
. J'ai ajouté la ligne[controller viewWillAppear:NO];
après et voilà! A fonctionné comme un charme.J'ai enfin trouvé une solution pour cela qui fonctionne!
UINavigationControllerDelegate
Je pense que l'essentiel est de définir le délégué de votre contrôle de navigation sur le contrôleur de vue dans lequel il se trouve, et de mettre en œuvre
UINavigationControllerDelegate
et ce sont deux méthodes. Brillant! Je suis tellement excité que j'ai enfin trouvé une solution!la source
J'ai juste eu le même problème. Dans mon application, j'ai 2 contrôleurs de navigation et pousser le même contrôleur de vue dans chacun d'eux fonctionnait dans un cas et pas dans l'autre. Je veux dire que lorsque vous appuyez sur le même contrôleur de vue dans le premier
UINavigationController
,viewWillAppear
été appelé mais pas lorsqu'il est enfoncé dans le deuxième contrôleur de navigation.Ensuite, je suis tombé sur ce post UINavigationController devrait appeler les méthodes viewWillAppear / viewWillDisappear
Et j'ai réalisé que mon deuxième contrôleur de navigation avait été redéfini
viewWillAppear
. Le filtrage du code a montré que je n'appelais pasJe l'ai ajouté et cela a fonctionné!
La documentation dit:
la source
J'utilise un contrôleur de navigation. Lorsque je souhaite descendre à un autre niveau de données ou afficher ma vue personnalisée, j'utilise ce qui suit:
Lorsque je fais cela, je
viewWillAppear
déclenche la fonction. Je suppose que cela se qualifie comme «indirect» parce que je n'appelle pasaddSubView
moi-même la méthode réelle . Je ne sais pas si cela s'applique à 100% à votre application car je ne peux pas dire si vous utilisez un contrôleur de navigation, mais peut-être que cela fournira un indice.la source
Merci iOS 13.
Les crédits vont à Arek Holko . Il a vraiment sauvé ma journée.
la source
Tout d'abord, la barre d'onglets doit être au niveau racine, c'est-à-dire ajoutée à la fenêtre, comme indiqué dans la documentation Apple. C'est la clé d'un comportement correct.
Deuxièmement, vous pouvez utiliser
UITabBarDelegate
/UINavigationBarDelegate
pour transférer les notifications manuellement, mais j'ai trouvé que pour que toute la hiérarchie des appels de vue fonctionne correctement, tout ce que j'avais à faire était d'appeler manuellementet
.. juste UNE FOIS avant de configurer les contrôleurs de vue sur le contrôleur respectif (juste après l'attribution). Dès lors, il a correctement appelé ces méthodes sur ses contrôleurs de vue enfants.
Ma hiérarchie est comme ceci:
Le simple fait d'appeler les méthodes mentionnées sur le contrôleur tab / nav la première fois garantissait que TOUS les événements étaient correctement transmis. Cela m'a empêché de devoir les appeler manuellement à partir des méthodes
UINavigationBarDelegate
/UITabBarControllerDelegate
.Sidenote: Curieusement, quand cela ne fonctionnait pas, la méthode privée
.. que vous pouvez voir à partir de la pile d'appels sur une implémentation de travail, appelle généralement les
viewWill/Did..
méthodes mais ne l'a pas fait jusqu'à ce que j'ai effectué ce qui précède (même si cela a été appelé).Je pense qu'il est TRÈS important que le
UITabBarController
soit au niveau de la fenêtre et les documents semblent étayer cela.J'espère que c'était clair (ish), heureux de répondre à d'autres questions.
la source
Comme aucune réponse n'est acceptée et que les gens (comme moi) atterrissent ici, je donne ma variante. Bien que je ne sois pas sûr que ce soit le problème initial. Lorsque le contrôleur de navigation est ajouté en tant que sous-vue à une autre vue, vous devez appeler vous-même les méthodes viewWillAppear / Dissappear etc. comme ceci:
Juste pour rendre l'exemple complet. Ce code apparaît dans mon ViewController où j'ai créé et ajouté le contrôleur de navigation dans une vue que j'ai placée sur la vue.
le .h ressemble à ceci
Dans le fichier nib, j'ai la vue et en dessous de cette vue, j'ai une étiquette une image et le conteneur (une autre vue) où je mets le contrôleur. Voici à quoi il ressemble. J'ai dû brouiller certaines choses car c'était du travail pour un client.
la source
Les vues sont ajoutées "directement" en appelant
[view addSubview:subview]
. Les vues sont ajoutées «indirectement» par des méthodes telles que les barres d'onglets ou les barres de navigation qui permutent les sous-vues.Chaque fois que vous appelez
[view addSubview:subviewController.view]
, vous devez alors appeler[subviewController viewWillAppear:NO]
(ou OUI selon votre cas).J'ai eu ce problème lorsque j'ai implémenté mon propre système de gestion personnalisé de la vue racine pour un sous-écran dans un jeu. L'ajout manuel de l'appel à viewWillAppear a résolu mon problème.
la source
La bonne façon de faire est d'utiliser l'api de confinement UIViewController.
la source
viewWillAppear:
peut toujours ne pas être appeléJ'utilise ce code pour les contrôleurs de vue push et pop:
pousser:
pop:
.. et cela fonctionne très bien pour moi.
la source
Une erreur très courante est la suivante. Vous avez un point de vue,
UIView* a
et un autre,UIView* b
. Vous ajoutez b à a en tant que sous-vue. Si vous essayez d'appeler viewWillAppear en b, il ne sera jamais déclenché, car il s'agit d'une sous-vue d'unla source
iOS 13 a mordu mon application dans le cul ici. Si vous avez remarqué un changement de comportement à partir d'iOS 13, définissez simplement ce qui suit avant de le pousser:
Vous devrez peut-être également le définir dans votre .storyboard dans l'inspecteur d'attributs (définissez Présentation sur Plein écran).
Cela permettra à votre application de se comporter comme dans les versions précédentes d'iOS.
la source
Je ne suis pas sûr à 100% à ce sujet, mais je pense que l'ajout d'une vue à la hiérarchie des vues signifie directement appeler
-addSubview:
la vue du contrôleur de vue (par exemple,[viewController.view addSubview:anotherViewController.view]
) au lieu de pousser un nouveau contrôleur de vue sur la pile du contrôleur de navigation.la source
Je pense que l'ajout d'une sous-vue ne signifie pas nécessairement que la vue apparaîtra, il n'y a donc pas d'appel automatique à la méthode de la classe pour qu'elle
la source
Je pense que ce qu'ils veulent dire "directement" est de raccorder les choses de la même manière que le modèle xcode "Navigation Application", qui définit UINavigationController comme la seule sous-vue de l'UIWindow de l'application.
L'utilisation de ce modèle est la seule façon dont j'ai pu obtenir les méthodes Will / Did / Apparear / Disappear appelées sur l'objet ViewControllers lors de la poussée / pop de ces contrôleurs dans UINavigationController. Aucune des autres solutions dans les réponses ici n'a fonctionné pour moi, y compris leur implémentation dans RootController et leur transmission au (enfant) NavigationController. Ces fonctions (vont / ont / apparaissent / disparaissent) n'ont été appelées dans mon RootController qu'après avoir affiché / masqué les VC de niveau supérieur, mes «login» et navigationVC, pas les sous-VC dans le contrôleur de navigation, donc je n'ai pas eu l'occasion de "les transmettre" au Nav VC.
J'ai fini par utiliser la fonctionnalité de délégué d'UINavigationController pour rechercher les transitions particulières qui nécessitaient une fonctionnalité de suivi dans mon application, et cela fonctionne, mais cela nécessite un peu plus de travail afin d'obtenir à la fois la fonctionnalité disparaître et apparaître "simulée".
C'est aussi une question de principe de le faire fonctionner après m'être cogné la tête contre ce problème pendant des heures aujourd'hui. Tout extrait de code fonctionnel utilisant un RootController personnalisé et un VC de navigation enfant serait très apprécié.
la source
Au cas où cela aiderait quelqu'un. J'ai eu un problème similaire où mon
ViewWillAppear
ne tire pas sur unUITableViewController
. Après avoir beaucoup joué, j'ai réalisé que le problème était que leUINavigationController
contrôle de monUITableView
n'est pas sur la vue racine. Une fois que j'ai corrigé cela, cela fonctionne maintenant comme un champion.la source
Je viens d'avoir ce problème moi-même et il m'a fallu 3 heures complètes (dont 2 sur Google) pour le résoudre.
Ce qui s'est avéré utile était simplement de supprimer l'application de l'appareil / simulateur, de la nettoyer puis de la relancer .
J'espère que cela pourra aider
la source
Définissez le délégué sur le contrôleur de vue racine.
la source
Pour Swift. Créez d'abord le protocole pour appeler ce que vous vouliez appeler dans viewWillAppear
Deuxièmement, créez la classe
}
Troisièmement, faites de l'instance de ForceUpdateOnViewAppear le membre de la classe appropriée qui a accès au contrôleur de navigation et existe tant que le contrôleur de navigation existe. Il peut s'agir par exemple du contrôleur de vue racine du contrôleur de navigation ou de la classe qui le crée ou le présente. Attribuez ensuite l'instance de ForceUpdateOnViewAppear à la propriété de délégué du contrôleur de navigation dès que possible.
la source
Dans mon cas, le problème était avec une animation de transition personnalisée. Lorsqu'il
modalPresentationStyle = .custom
viewWillAppear
n'est pas appelédans la classe d'animation de transition personnalisée ont besoin de méthodes d'appel:
beginAppearanceTransition
etendAppearanceTransition
la source
Dans mon cas, ce n'était qu'un bug étrange sur l'émulateur ios 12.1. Disparu après le lancement sur un appareil réel.
la source
J'ai créé une classe qui résout ce problème. Définissez-le simplement comme délégué de votre contrôleur de navigation et implémentez une ou deux méthodes simples dans votre contrôleur de vue - qui seront appelées lorsque la vue est sur le point d'être affichée ou a été affichée via NavigationController
Voici le GIST montrant le code
la source
ViewWillAppear est une méthode de substitution de la classe UIViewController, donc l'ajout d'un sousView n'appellera pas viewWillAppear, mais lorsque vous présentez, push, pop, show, setFront Ou popToRootViewController à partir d'un viewController, alors viewWillAppear pour le viewController présenté sera appelé.
la source
Mon problème était que viewWillAppear n'était pas appelé lors du déroulement d'un segue. La réponse était de mettre un appel à viewWillAppear (true) dans la séquence de déroulement dans le contrôleur de vue auquel vous revenez
@IBAction func unind (pour unindSegue: UIStoryboardSegue, ViewController nextVC: Any) {
la source
Je ne suis pas sûr que ce soit le même problème que j'ai résolu.
Dans certaines occasions, la méthode ne s'exécute pas de manière normale comme "[self methodOne]".
Essayer
la source
viewWillAppear
pas du tout appeléVous ne devriez avoir qu'un seul UIViewController actif à tout moment. Toutes les sous-vues que vous souhaitez manipuler doivent être exactement cela - subVIEWS - c'est-à-dire UIView.
J'utilise une technique simple pour gérer ma hiérarchie de vues et je n'ai pas encore rencontré de problème depuis que j'ai commencé à faire les choses de cette façon. Il y a 2 points clés:
Qu'est-ce que j'entends par «la valeur d'un écran»? C'est un peu vague exprès, mais il s'agit généralement d'une fonctionnalité ou d'une section de votre application. Si vous avez quelques écrans avec la même image d'arrière-plan mais des superpositions / fenêtres contextuelles différentes, etc., cela devrait être 1 contrôleur de vue et plusieurs vues enfants. Vous ne devriez jamais travailler avec 2 contrôleurs de vue. Notez que vous pouvez toujours instancier un UIView dans un contrôleur de vue et l'ajouter en tant que sous-vue d'un autre contrôleur de vue si vous souhaitez que certaines zones de l'écran soient affichées dans plusieurs contrôleurs de vue.
Quant à UINavigationController - c'est votre meilleur ami! Désactivez la barre de navigation et spécifiez NON pour les animations, et vous disposez d'un excellent moyen de changer d'écran à la demande. Vous pouvez pousser et afficher les contrôleurs de vue s'ils se trouvent dans une hiérarchie, ou vous pouvez préparer un tableau de contrôleurs de vue (y compris un tableau contenant un seul VC) et le définir comme la pile de vues à l'aide de setViewControllers. Cela vous donne une liberté totale pour changer les VC, tout en bénéficiant de tous les avantages de travailler dans le modèle attendu d'Apple et de déclencher correctement tous les événements, etc.
Voici ce que je fais à chaque fois que je lance une application:
(notez que le départ basé sur la fenêtre est juste une préférence personnelle - j'aime construire des choses moi-même pour savoir exactement comment elles sont construites. Cela devrait fonctionner correctement avec un modèle basé sur la vue)
Tous les événements se déclenchent correctement et fondamentalement, la vie est belle. Vous pouvez ensuite passer tout votre temps à écrire les éléments importants de votre application sans vous soucier d'essayer de pirater manuellement les hiérarchies de vue.
la source