La manera más simple y correcta de cambiar las vistas de forma no modal, utilizando storyboards

Soy completamente nuevo en el desarrollo de iOS y todavía no he logrado cómo llevar a cabo una tarea tan fácil.

Tengo un proyecto xCode 4.4.1 "Vista única".

Quiero tener, por ejemplo, cuatro pantallas, cada una con botones para cambiar a otras vistas.

Las pantallas no están configuradas en una jerarquía: por ejemplo, quiero poder cambiar a la pantalla 2 o a la pantalla 3 de la pantalla 1, a la pantalla 4 de la pantalla 2, y así sucesivamente. En la ejecución de la aplicación, se muestra la primera pantalla, pero su estado no es "raíz" o "principal", es solo una pantalla común entre otras.

Mis condiciones son:

  1. Solo tengo el file pnetworkingeterminado de storyboard principal (las soluciones xib no están bien).
  2. No quiero confiar en usar controlleres de navigation o cosas pre-estructuradas similares.

Me parece que necesito configurar el controller de contenedor con controlleres secundarios tal como se describen en la Sesión 102 de WWDC 2011, pero no entiendo cómo escribir correctamente el código, por lo que no entrará en conflicto con el Storyboard principal ( Tengo dos bashs fallidos de usar soluciones basadas en xib de otros temas similares aquí en SO).

Apreciaría mucho un ejemplo de trabajo completo, debido a mi experiencia, todavía no me permite confiar en pistas parciales, aunque también estarán bien.

Se prefiere una solución que lo haga mediante progtwigción (no usar las características de interfaz de usuario xCode como arrastrar).

¡Gracias!

ACTUALIZACIÓN: al cambiar, no deseo instanciar nuevas pantallas cada vez, sino reutilizar las existentes, si ya existen.

ACTUALIZACIÓN 2: Mi caso de uso, simplificado para este problema:

Tengo una pantalla de logging, con pantallas modal correspondientes para manejar todas las situaciones comunes de inicio de session / cierre de session / etc. Y tengo la pantalla principal de mi aplicación, que se convierte en la pantalla de la aplicación "principal" una vez finalizado el process de inicio de session / logging. No quiero hacer que la pantalla / controller de logging sea modal para la pantalla principal, ya que la pantalla principal depende mucho de la información específica del usuario, por lo que me gustaría tener estas pantallas no organizadas de forma jerárquica. Pienso en tener el siguiente flujo para esta situación simplificada:

1) El usuario aún no ha iniciado session – se presenta la pantalla de logging. Más tarde, después de reg. El procedimiento está hecho: cambie (este es un punto key del que no estoy enterado, es por eso que este problema) a la pantalla "principal".

2) El usuario ha iniciado session y la aplicación lo reconoce: se presenta la pantalla "principal".

Tener el logging y las pantallas "principales" como describí excluyen (o ¿qué?) La situación de tener la funcionalidad de "controller de tabs" en la plantilla "Aplicación con tabs" tal como está, porque en mi caso quiero tener la barra de tabs completamente deshabilitada, lo que necesito No es una nav. y funcionalidad de barra de navigation, pero solo la forma de realizar la transición entre reg. y pantallas "principales", esto es lo que quiero decir "con las manos" en mi pregunta.

ACTUALIZACIÓN FINAL:

Después de experimentar con el controller de barra de tabs, para este caso de uso, he terminado utilizando el controller de navigation con la barra de navigation deshabilitada (no encontré una similar en el controller de barra de tabs) y la gestión de la conmutación de pantallas mediante el método performSegueWithIdentifier , así como el cambio manipulando la stack de navigation viewControllers "con las manos".

¡Gracias a todos por las respuestas!

Probablemente lo más fácil es usar segues en el guión gráfico.

haga clic con el button derecho y arrastre desde su controller de vista principal a cada uno de los demás. Preguntará qué tipo de segue crear y elegir modal.

Luego, asegúrese de dar a cada una de las segues una cadena de identificador único en la propiedad de identificador.

Ahora, desde el código, en cualquier momento que desee que uno de esos controlleres de vista se active, llame al

[self performSegueWithIdentifier:@"Foo Segue" sender:(id)sender]; 

El object remitente de arriba puede ser cualquier cosa que desee, por lo general, cierta información que desea transmitir al controller de vista que se está preparando para que se muestre.

Ahora, justo antes de que se muestre una segue, ya sea progtwigda o directamente desde la interacción definida por el guión gráfico, se prepareForSegue método prepareForSegue . Entonces, haría algo como esto, nuevamente en el código del controller de vista "principal".

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // You have access to the view controller that is getting ready to be // displayed, as well as the identifier, so you can set values or whatever // before the view controller is presented. if ([segue.identifier isEqualToString:@"Foo Segue"]) { FooViewController *vc = segue.destinationViewController; // The view controller is completely instantiated, and you can do any // setup work, like setting property values on the view controller // to give it its model, or whatever else you want to do. } } 

Ahora, necesita alguna forma de saber cuándo se hace ese controller. Esto se puede hacer de varias maneras. El controller de vista presentado puede descartarse, o puede usar un delegado o notificación para decirle al controller de vista que está hecho y debe ser descartado.

En su caso, puede estar bien dejar que el VC presentado se excluya. Entonces, solo llama

 [self dismissViewControllerAnimated:YES completion:nil]; 

Si no quieres usar segues, tendrás que cargar tus VC directamente desde el guión gráfico (o darles su propia punta). Para crear una instancia desde el guión gráfico, debe proporcionar a los controlleres de vista que desee crear una instancia de su propia label de identificación (busque nuevamente en el panel de properties y establezca la propiedad en el VC).

Entonces puede hacer esto (suponiendo que el VC que aloja este código está en el mismo guión gráfico que el VC al que intenta instanciar) …

 FooViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"FooViewController"]; 

Entonces, usted realmente presenta ese controller con …

 [self presentViewController:vc animated:YES completion:nil]; 

Por supuesto, hay varias otras forms de hacer esto, y hay algunas ventajas / desventajas en cada enfoque. Sugiero que juegue con él y lea la documentation asociada para que pueda tomar una decisión educada sobre qué método usar.

En cualquier caso, lo anterior debería darle un path algo fácil hacia su objective.

La respuesta corta a su pregunta es usar un controller de barra de tabs. Este es un control simple que realmente gestiona mucha complejidad, y su reimplementación no es una buena idea para un principiante, o para los usuarios de su aplicación, que estarán acostumbrados a cómo funciona un controller de barra de tabs.

El controller de la barra de tabs tiene una propiedad ( viewControllers ) que puede completar en el guión gráfico al arrastrar el control a sus otras escenas. El controller de barra de pestaña interroga a cada uno de estos controlleres de vista para crear la barra de tabs (nombres e imágenes, la cantidad apropiada de elementos, un controller "Más" si hay demasiados para caber en la barra) y maneja el cambio entre cada uno de ellos, alterando el tamaño de las vistas contenidas y la barra de tabs para manejar los events de rotation. La vista del controller de barra de tabs, por lo tanto, contiene dos subvistas: una para mantener presionada la barra de tabs y otra para mantener la vista del controller de vista que se muestra actualmente.

Tendrías que duplicar toda esa funcionalidad tú mismo, lo cual es bastante complicado para un principiante, y ciertamente está fuera del scope de una respuesta de Desbordamiento de stack. El hecho de que esté duplicando la funcionalidad existente también debería ser una señal roja si realmente debería estar trabajando de esa manera.

La implementación de un controller de tipo tab bar usted mismo no es compatible con storyboards, ya que la parte key (la "Relación – Controladores de vista") no está disponible para los controlleres de vista de contenedor personalizados. Por lo tanto, tendría que configurar su interfaz de usuario en código e instanciar manualmente los controlleres de visualización para configurar la relación, lo que bien podría entrar en conflicto con su guión gráfico principal, aunque su oración sobre preferir hacer esto clasifica programáticamente con la request del guión gráfico en El título de la pregunta, así que estoy un poco confundido por eso.

Una breve descripción de cómo podría implementar esto si aún desea:

  • Cree un UIViewController personalizado
  • Agregue una propiedad viewControllers y algún tipo de control para manejar la conmutación, probablemente un control segmentado
  • Cuando se establece la propiedad viewControllers , obtenga el título para establecerlo como el título de uno de sus segmentos de control segmentados. Agregue la vista del primer elemento en la matriz como una subvista de su vista principal (con el marco apropiado para que no cubra su control segmentado) y agréguelo como un controller de vista secundario utilizando [self addChildViewController:vc] y [vc didMoveToParentViewController:self] )
  • Cuando el valor del control segmentado cambia, quite la vista del controller de vista actual de la jerarquía de vista ( removeFromSuperview ) y la jerarquía del controller de vista ( removeFromParentViewController ), y agregue la vista del controller de vista recién seleccionada utilizando el código anterior.