2012-03-16 19 views
32

Configuración: Tengo un guión gráfico configurado, con dos controladores simples de vista A y B. Hay un botón en A, que pasa a B con una transición modal. B se presenta con una transición modal en la parte superior de A. Está bien.¿Cómo descartar un modal que se presentó en un UIStoryboard con una transición modal?

Pregunta: ¿hay alguna manera de hacer estallar B y volver a A con un poco de magia simple del guión gráfico?

Tenga en cuenta que si todo esto estuviera en un controlador de navegación, y utilicé un segue de inserción, sería implícitamente atendido por el controlador de navegación. Habría un botón "atrás". No hay nada comparable para los modales, necesito construir la interfaz de usuario, lo cual está bien, pero me pregunto si hay una mecánica de segue que pueda usar para señalar que regrese de B a A.

Ahora el método oldskool para construir volver de B a a sería:

  • crear una propiedad delegado en B
  • conjunto a para ser delegado de B cuando el segue transición modal reproduce (puedo enlazar en esta usando prepareForSegue: remitente: en una de código)
  • cuando es hora de despedir, B señala a su delegado
  • A implementa un método delegado que descarta B

Esto funciona, pero se siente como demasiado por encima y tonto.

¿Hay alguna mecánica UIStoryboard que me he perdido, que básicamente haría una "transición modal inversa"?

Respuesta

44

No hay magia en el guión gráfico para descartar un controlador de vista modal sin escribir al menos un poquito de código.

Pero si bien tiene que implementar algún código propio, no necesariamente tiene que tomarse tantas molestias. Solo puede tener un botón en el controlador de vista B que llame al [self dismissViewControllerAnimated:YES completion:nil]. (Los documentos dicen que el controlador de visualización de presentación debe ser el que se descarta, pero también dicen que el mensaje se reenviará al controlador de vista de presentación si se llama al presente. Si quieres ser más explícito al respecto, y tú " ll tienen que ser, en algunos casos, como cuando controlador de vista de un modal se presenta de otro - se puede hacer referencia explícitamente al presentador con self.presentingViewController y llame dismiss... desde allí)

que vea el negocio delegado en algunas aplicaciones porque es uno. forma de notificar al controlador de vista A sobre lo que hizo el usuario mientras estaba en el controlador de vista B ... pero no es la única manera. Hay KVO, notificaciones, o simplemente llamando a los métodos de A después de hacer referencia a él con self.presentingViewController (asumiendo que B sabe que siempre se presenta por A). Y si A no necesita saber lo que sucedió en B (digamos, porque el usuario pulsa el botón Cancelar), no hay necesidad de hacer nada de eso; simplemente puede descartar el modal y terminarlo.


En iOS 6 y más tarde, relajarse segues añaden otra opción, proporcionando un poco de "magia guión gráfico" para despedir controladores de vista modal (o de otra manera "Copia out" de una secuencia de segues). Pero este enfoque aún requiere un código: no se puede configurar por completo en el guión gráfico. En el lado positivo, sin embargo, ese código proporciona una ruta para obtener información del controlador de vista que se descarta (B) a la que lo presentó (A).

Apple tiene a tech note about unwind segues que los cubre en detalle, pero aquí está la versión corta:

  1. definir un método IBAction de la clase de controlador de vista desea relajarse a - el que presenta un modal ver el controlador, no el controlador de vista modal en sí (ver el controlador A en su pregunta). A diferencia de los métodos normales IBAction, estos deben tomar un parámetro del tipo UIStoryboardSegue *; p.ej.

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender 
    
  2. En el controlador de vista presentado (B en la pregunta), alambre de un control para el icono verde de la salida, y elija el método que ha definido.

  3. En su implementación de método de desenrollado, puede consultar el sourceViewController de segue para recuperar información del controlador de vista que se está descartando. No es necesario que llame al dismissViewControllerAnimated:completion: porque la segue trata de descartar el controlador de vista que se va.

+0

Genial, no sabía acerca de la presentación de ViewController (aparentemente una nueva cosa de iOS 5), eso ayuda. – Jaanus

+2

Sí, si desea hacer esto en una transición personalizada para una fácil reutilización, puede hacer algo como - (nulo) realizar { UIViewController * src = (UIViewController *) self.sourceViewController; [src.presentingViewController dismissModalViewControllerAnimated: YES]; } – AppHandwerker

+0

@SimonH ¡El mejor consejo con respecto a los segues! –

30

Hay es magia del guión gráfico para lograrlo. Es conocido como un segue de desenrollar. En el archivo .h de A, implemente los métodos de estilo de "acción de destino" que necesite para cuantos segmentos de desenrollado necesite. Para un modal, por lo general es dos (cancelar y guardar). Así que en mi archivo Ah yo añadiría:

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

Ahora, en el guión gráfico, si usted tiene un segue de A a B. Ahora puede hacer una "acción de destino" arrastrar control de estilo de sus botones de cancelar/guardar en B al ícono verde "Salir" en la parte inferior del controlador B en su guión gráfico. Cuando hagas esto, Xcode recogerá los dos métodos que creamos (ya que están en el archivo de encabezado de A y tienen la firma correcta (por ejemplo, IBAction y UIStoryboardSegue *.) Y B es el destino de una transición de A). ahí tienes. ¡Tienes la magia del guión gráfico que estabas buscando!

En la aplicación de las dos devoluciones de llamada, usted tendría algo como:

// 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... 
} 

Por último, si este enfoque se adapte a sus necesidades, muy bien. Ya terminaste Sin embargo, todavía cableo el patrón de diseño delegado/fuente de datos del protocolo completo si "on cancel" o "on save" deseo realizar algunas operaciones en las propiedades privadas de B antes de pasar el control a A para eliminar B de la jerarquía de vista.

+1

tenga en cuenta 2 cosas: 1) en la devolución de llamada no hay necesidad de descartar modal porque será descartado automáticamente por desenrollar segue (y causará error si lo intenta) 2) desenrollar acciones segue (botón de salida verde) trabajar con iOS6 objetivo. es un poco confuso porque con el objetivo más viejo verás el botón de salida verde que no tiene sentido) –

+1

Esa no es realmente la "magia del guión gráfico" porque todavía tienes que agregar código a tu controlador A view. Pero en mi caso, B es solo contenido estático, por lo que es mejor tener que crear una subclase de controlador de vista B solo para descartarla. – jab

Cuestiones relacionadas