web-dev-qa-db-fra.com

Comment rejeter un modal présenté dans un UIStoryboard avec une séquence modale?

Configuration: J'ai un storyboard configuré, avec deux contrôleurs de vue simples A et B. Il y a un bouton dans A, qui passe à B avec une séquence modale. B est présenté avec une transition modale au-dessus de A. C'est bien.

Question: existe-t-il un moyen de faire disparaître B et de revenir à A avec une simple magie de storyboard?

Notez que si tout cela était dans un contrôleur de navigation, et que j'utilisais une séquence Push, ce serait implicitement pris en charge par le contrôleur de navigation. Il y aurait un bouton "retour". Il n'y a rien de comparable pour les modaux, je dois construire l'interface utilisateur moi-même, ce qui est bien, mais je me demande s'il y a un mécanisme de transition que je peux utiliser pour signaler de revenir de B à A.

Maintenant, la méthode oldskool pour construire en revenant de B à A serait:

  • créer une propriété de délégué sur B
  • définir A comme délégué de B lors de la lecture de la transition de transition modale (je peux y accéder en utilisant prepareForSegue: sender: dans le code de A)
  • quand il est temps de licencier, B fait signe à son délégué
  • A implémente une méthode déléguée qui rejette B

Cela fonctionne, mais semble trop lourd et idiot.

Y a-t-il un mécanicien UIStoryboard que j'ai manqué, qui ferait essentiellement une "séquence modale inversée"?

32
Jaanus

Il n'y a pas de magie de storyboard pour rejeter un contrôleur de vue modale sans écrire au moins un peu de code.

Mais même si vous devez implémenter votre propre code, vous n'avez pas nécessairement à vous embêter autant. Vous pouvez simplement avoir un bouton dans le contrôleur de vue B qui appelle [self dismissViewControllerAnimated:YES completion:nil]. (Les documents indiquent que le contrôleur de vue présentateur doit être celui à rejeter, mais ils disent également que le message sera transmis au contrôleur de vue présenté s'il est appelé par le présentateur. Si vous voulez être plus explicite à ce sujet - et vous '' ll doit l'être dans certains cas, comme lorsqu'un contrôleur de vue modale est présenté à partir d'un autre - vous pouvez explicitement référencer le présentateur avec self.presentingViewController et appelez dismiss... De là.)

Vous voyez l'entreprise déléguée dans certaines applications, car c'est une façon d'aviser le contrôleur de vue A de tout ce que l'utilisateur a fait lorsqu'il était dans le contrôleur de vue B ... mais ce n'est pas le seul moyen. Il y a KVO, des notifications ou simplement appeler les méthodes de A après l'avoir référencé avec self.presentingViewController (en supposant que B sait qu'il est toujours présenté par A). Et si A n'a pas besoin de savoir ce qui s'est passé dans B (disons, parce que l'utilisateur a appuyé sur un bouton Annuler), il n'y a pas besoin de faire tout cela - vous pouvez simplement ignorer le modal et en finir.


Dans iOS 6 et versions ultérieures, les séquences de déroulement ajoutent une autre option, fournissant un peu de "magie de storyboard" pour rejeter les contrôleurs de vue modale (ou autrement "reculer" d'une séquence de séquences). Mais cette approche nécessite toujours du code - vous ne pouvez pas le configurer entièrement dans le storyboard. Du côté positif, cependant, ce code fournit un chemin pour obtenir des informations du contrôleur de vue rejeté (B) à celui qui l'a présenté (A).

Apple a ne note technique sur les séquences de déroulement qui les couvre en détail, mais voici la version courte:

  1. Définissez une méthode IBAction sur la classe de contrôleur de vue que vous souhaitez dérouler en - celle qui présente un contrôleur de vue modale, pas le contrôleur de vue modal lui-même (voir le contrôleur A dans votre question). Contrairement aux méthodes normales de IBAction, celles-ci doivent prendre un paramètre de type UIStoryboardSegue *; par exemple.

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
    
  2. Dans le contrôleur de vue présenté (B dans la question), connectez un contrôle à l'icône de sortie verte et choisissez la méthode que vous avez définie.

  3. Dans votre implémentation de la méthode de déroulement, vous pouvez vous référer au sourceViewController du segue pour récupérer les informations du contrôleur de vue en cours de fermeture. Vous n'avez pas besoin d'appeler dismissViewControllerAnimated:completion: car le segue gère le rejet du contrôleur de vue qui s'en va.

44
rickster

Il y a = magie de storyboard pour y parvenir. Il est connu comme une séquence de déroulement. Dans le fichier .h de A, vous implémentez les méthodes de style "action cible" dont vous avez besoin pour le nombre de séquences de déroulement dont vous avez besoin. Pour un modal, c'est généralement deux (annuler et enregistrer). Donc, dans mon fichier A.h, j'ajouterais:

// A.h file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue;
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue;

Maintenant, dans votre storyboard, si vous avez un enchaînement de A à B. Vous pouvez maintenant faire un contrôle de style "action cible" faire glisser depuis vos boutons annuler/enregistrer en B vers l'icône verte "Quitter" en bas du contrôleur B dans votre storyboard. Lorsque vous faites cela, Xcode récupérera les deux méthodes que nous avons créées (car elles sont dans le fichier d'en-tête de A et elles ont la signature correcte (par exemple IBAction et UIStoryboardSegue *.)) Et B est la destination d'une séquence de A) Donc, Voilà. Vous avez la magie du storyboard que vous cherchiez!

Dans la mise en œuvre des deux rappels, vous auriez quelque chose comme:

// A.m file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

Enfin, si cette approche répond à vos besoins, tant mieux. Vous avez terminé. Cependant, je continue de câbler l'ensemble du modèle de conception délégué/dataSource du protocole si "sur annuler" ou "sur enregistrer" je souhaite effectuer certaines opérations sur les propriétés privées de B avant de passer le contrôle à A pour supprimer B de la hiérarchie des vues.

30
John Erck