J'ai lu de nombreux articles sur des personnes ayant des problèmes avec viewWillAppear
lorsque vous ne créez pas votre hiérarchie de vues juste right. Mon problème est que je ne peux pas comprendre ce que cela signifie.
Si je crée une RootViewController
et appelle addSubView
sur ce contrôleur, les vues ajoutées seront câblées pour les événements viewWillAppear
.
Quelqu'un a-t-il un exemple de hiérarchie complexe de vues programmatiques recevant avec succès des événements viewWillAppear
à tous les niveaux?
État de la documentation d'Apple:
Avertissement: Si la vue appartenant à un contrôleur de vue est ajoutée directement à une hiérarchie de vues, ce dernier ne recevra pas ce message. Si vous insérez ou ajoutez une vue à la hiérarchie de vues et que celle-ci comporte un contrôleur de vue, vous devez envoyer ce message directement au contrôleur de vue associé. À défaut d'envoyer ce message au contrôleur de la vue, toute animation associée ne sera pas affichée.
Le problème est qu'ils ne décrivent pas comment faire cela. Que signifie "directement"? Comment ajoutez-vous "indirectement" une vue?
Je suis assez nouveau pour Cocoa et iPhone, alors ce serait bien s'il y avait des exemples utiles d'Apple en plus de la merde de base de Hello World.
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égation du contrôleur de navigation à la place:
navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
J'ai rencontré ce même problème. Envoyez simplement un message viewWillAppear
à votre contrôleur de vue avant de l'ajouter en tant que sous-vue. (Un paramètre BOOL indique au contrôleur de vue s'il est animé ou non.)
[myViewController viewWillAppear:NO];
Regardez RootViewController.m dans l'exemple Metronome.
(En fait, j'ai trouvé les exemples de projets d'Apple excellents. Il y a beaucoup plus que HelloWorld;)
J'ai finalement trouvé une solution pour ce 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 d’implémenter UINavigationControllerDelegate
et ses deux méthodes. Brillant! Je suis tellement excitée d'avoir enfin trouvé une solution!
Je viens d'avoir le même problème. Dans mon application, j'ai 2 contrôleurs de navigation et le même contrôleur de vue dans chacun d'eux a fonctionné dans un cas et non dans l'autre. Je veux dire que lorsque vous appuyez exactement sur le même contrôleur de vue dans la première UINavigationController
, viewWillAppear
a été appelé, mais pas lorsque vous avez poussé le second contrôleur de navigation.
Puis je suis tombé sur ce post UINavigationController doit appeler les méthodes viewWillAppear/viewWillDisappear
Et réalisé que mon deuxième contrôleur de navigation a redéfini viewWillAppear
. Le filtrage du code a montré que je n'appelais pas
[super viewWillAppear:animated];
Je l'ai ajouté et cela a fonctionné!
La documentation dit:
Si vous substituez cette méthode, vous devez appeler super à un moment donné de votre implémentation.
J'ai utilisé un contrôleur de navigation. Lorsque je souhaite descendre à un autre niveau de données ou afficher ma vue personnalisée, j'utilise les éléments suivants:
[self.navigationController pushViewController:<view> animated:<BOOL>];
Lorsque je le fais, la fonction viewWillAppear
est activée. Je suppose que cela est considéré comme "indirect" parce que je n’appelle pas moi-même la méthode addSubView
. 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 cela vous donnera peut-être un indice.
Tout d'abord, la barre d'onglets doit être située 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 constaté que pour que toute la hiérarchie des appels de vue fonctionne correctement, il me suffisait d’appeler manuellement.
[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];
et
[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];
.. juste une fois avant de configurer les contrôleurs de vue sur le contrôleur respectif (juste après l'attribution). À partir de là, il a correctement appelé ces méthodes sur ses contrôleurs de vue enfant.
Ma hiérarchie est comme ça:
window
UITabBarController (subclass of)
UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
UINavigationController (subclass of)
UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods
Le simple fait d'appeler les méthodes mentionnées sur le contrôleur de tabulation/navigation pour la première fois garantissait que TOUS les événements étaient transférés correctement. Cela m'a évité de devoir les appeler manuellement à partir des méthodes UINavigationBarDelegate
/UITabBarControllerDelegate
.
Sidenote: Curieusement, quand ça ne marchait pas, la méthode privée
- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController
.. que vous pouvez voir depuis le callstack sur une implémentation qui fonctionne, appelle généralement les méthodes viewWill/Did..
mais ne l’a pas fait jusqu’à ce que j’ai effectué ce qui précède (même si elle a été appelée).
Je pense qu'il est TRÈS important que la UITabBarController
soit au niveau de la fenêtre et que les documents semblent le confirmer.
J'espère que c'était clair (ish), heureux de répondre à d'autres questions.
Les vues sont ajoutées "directement" en appelant [view addSubview:subview]
. Les vues sont ajoutées "indirectement" à l'aide de méthodes telles que les barres de tabulation 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 bien OUI selon votre cas).
J'ai eu ce problème lorsque j'ai implémenté mon propre système de gestion de vue racine personnalisé pour un sous-écran dans un jeu. Ajouter manuellement l'appel à viewWillAppear a résolu mon problème.
Pour ce faire, utilisez l’API de confinement UIViewController.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIViewController *viewController = ...;
[self addChildViewController:viewController];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
}
Comme aucune réponse n'est acceptée et que des 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 les méthodes viewWillAppear/Dissappear etc.
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[subNavCntlr viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[subNavCntlr viewWillDisappear:animated];
}
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.
- (void)viewDidLoad {
// This is the root View Controller
rootTable *rootTableController = [[rootTable alloc]
initWithStyle:UITableViewStyleGrouped];
subNavCntlr = [[UINavigationController alloc]
initWithRootViewController:rootTableController];
[rootTableController release];
subNavCntlr.view.frame = subNavContainer.bounds;
[subNavContainer addSubview:subNavCntlr.view];
[super viewDidLoad];
}
le .h ressemble à ceci
@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
IBOutlet UIView *subNavContainer;
UINavigationController *subNavCntlr;
}
@end
Dans le fichier nib, j'ai la vue et sous cette vue, j'ai une étiquette une image et le conteneur (une autre vue) où je mets le contrôleur. J'ai dû brouiller certaines choses car c'était un travail pour un client.
Merci iOS 13.
ViewWillDisappear
,ViewDidDisappear
,ViewWillAppear
etViewDidAppear
ne seront pas appelés sur un contrôleur de présentation sur iOS 13 qui utilise une nouvelle présentation modale qui ne couvre pas tout l'écran. .
Les crédits vont à Arek Holko . Il a vraiment sauvé ma journée.
J'utilise ce code pour les contrôleurs de vue Push et Pop:
Pousser:
[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];
pop:
[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];
.. et ça marche bien pour moi.
Une erreur très courante est la suivante ... vous avez une vue, UIView* a
, et une autre, UIView* b
. Vous ajoutez b à a en tant que sous-vue . Si vous essayez d'appeler viewWillAppear dans b, il sera ne jamais être congédié, car il s'agit d'une sous-vue d'un
[self.navigationController setDelegate:self];
Définissez le délégué sur le contrôleur de vue racine.
Pour Swift. Commencez par créer le protocole pour appeler ce que vous voulez appeler dans viewWillAppear
protocol MyViewWillAppearProtocol{func myViewWillAppear()}
Deuxièmement, créer la classe
class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
updatedCntllr.myViewWillAppear()
}
}
}
Troisièmement, faites de l'instance de ForceUpdateOnViewAppear le membre de la classe appropriée ayant accès au contrôleur de navigation et existe tant que le contrôleur de navigation existe. Ce peut être par exemple le contrôleur de vue racine du contrôleur de navigation ou la classe qui le crée ou le présente. Affectez ensuite l'instance de ForceUpdateOnViewAppear à la propriété de délégué du contrôleur de navigation le plus tôt possible.
Je pense que l'ajout d'une sous-vue ne signifie pas nécessairement que la vue va apparaître. Il n'y a donc pas d'appel automatique à la méthode de la classe.
Je pense que ce qu'ils veulent dire "directement" est en liant les choses de la même manière que le modèle xcode "Application de navigation", qui définit UINavigationController comme unique sous-vue de UIWindow de l'application.
L'utilisation de ce modèle est le seul moyen d'obtenir les méthodes Will/Did/Apparaître/Désapparaître appelées sur l'objet ViewControllers lors du Push/Pop de ces contrôleurs dans UINavigationController. Aucune des autres solutions dans les réponses ici ne fonctionnait pour moi, y compris leur implémentation dans RootController et leur transmission à (l'enfant) NavigationController. Ces fonctions (volonté/apparition/disparition) n’ont été appelées dans mon RootController qu’après avoir affiché/masqué les VCs de niveau supérieur, mes "identifiants" et navigateursCV, et non les sous-VCs du contrôleur de navigation. "les passer" au Nav VC.
J'ai fini par utiliser la fonctionnalité de délégué de 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 pour obtenir à la fois la fonctionnalité de disparition et d'affichage "simulée".
Aussi, c'est une question de principe de le faire fonctionner après m'être cogné la tête contre ce problème pendant des heures. Tous les extraits de code fonctionnels utilisant un RootController personnalisé et une navigation enfant VC seraient grandement appréciés.
Au cas où cela aiderait quelqu'un. J'ai eu un problème similaire où ma ViewWillAppear
ne tire pas sur une UITableViewController
. Après avoir beaucoup joué, je me suis rendu compte que le problème était que la UINavigationController
qui contrôle ma UITableView
ne se trouvait pas dans la vue racine. Une fois que j'ai résolu ce problème, cela fonctionne maintenant comme un champion.
Je viens d'avoir ce problème moi-même et il m'a fallu 3 heures complètes (dont 2 googler) pour résoudre ce problème.
Ce qui s’est avéré utile, c’est tout simplement de supprimer l’application de l’appareil/simulateur, de la nettoyer puis de la relancer.
J'espère que cela pourra aider
Je ne suis pas tout à fait sûr à ce sujet, mais je pense que l'ajout d'une vue à la hiérarchie consiste à appeler -addSubview:
dans la vue du contrôleur de vue (par exemple, [viewController.view addSubview:anotherViewController.view]
) au lieu de placer un nouveau contrôleur de vue dans la pile du contrôleur de navigation.
ViewWillAppear est une méthode de substitution de la classe UIViewController. Par conséquent, l'ajout d'une sous-vue n'appelle pas viewWillAppear, mais vous devez appeler Push, pop, show, setFront ou popToRootViewController.
J'ai créé une classe qui résout ce problème. Définissez-le simplement en tant que 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
Dans mon cas, il s’agissait d’un étrange bug sur l’émulateur iOS 12.1. Disparu après le lancement sur un périphérique réel.
Dans mon cas, le problème était lié à l’animation de transition personnalisée . Lorsque modalPresentationStyle = .custom
viewWillAppear
était défini
dans la classe d'animation de transition personnalisée, il faut utiliser les méthodes suivantes: beginAppearanceTransition
et endAppearanceTransition