tutorial que containerview container apple ios xcode cocoa-touch uiviewcontroller uistoryboard

ios - que - use container view swift 4



Vinculación de controladores de vista secundarios a un controlador de vista principal dentro del guión gráfico (5)

¿Puede asociar los controladores de vista infantil a un controlador de vista de contenedor personalizado en Storyboard?

Creo que lo que estás preguntando aquí es cómo conectar un controlador de visualización en una escena a una salida de un controlador de visualización en una escena diferente. No creo que eso sea posible, tal vez porque la maquinaria del guión gráfico puede no tener todas las escenas en un guión gráfico cargadas al mismo tiempo.

Probablemente estés preguntando esto porque quieres pasar información de un controlador de vista a otro a medida que pasas de una escena a la siguiente. La forma de hacerlo cuando trabajas con guiones gráficos es redefinir -prepareForSegue:sender: en uno o en ambos controladores de vista afectados por el segue. El objeto UIStoryboardSegue proporcionado en el parámetro segue tiene las propiedades sourceViewController y destinationViewController , y también una propiedad de identifier . Puede usar estas propiedades para identificar el segue que está a punto de transferir datos entre los controladores de vista.

El blog de Ray Wenderlich tiene un buen tutorial en dos partes sobre el uso de guiones gráficos que pueden ayudarlo a:

  • La Parte 1 cubre la configuración de un proyecto de guión gráfico, la adición de escenas y la creación de segues.

  • La Parte 2 trata con el uso de segues para la transición entre escenas, incluido el método prepareForSeque mencionado anteriormente.

iOS 5 permite que varios controladores de vista estén activos en la misma escena (aunque uno todavía debe estar a cargo), por lo que una sola escena en su guión gráfico podría tener varios controladores. Puede usar los enchufes para conectar estos controladores entre sí, y puede configurar esas conexiones de la misma manera que lo hizo en IB: control-arrastre de un controlador a otro en la misma escena. La lista de salida habitual se abrirá para que pueda elegir qué salida conectar.

¿Puede asociar los controladores de vista infantil a un controlador de vista de contenedor personalizado en Storyboard?

Puedo vincular los controladores de vista infantil a un controlador de vista de pestañas, y puedo vincular un controlador de vista a un controlador de navegación.

¿Qué debo hacer para que el contenedor VC acepte VCs infantiles?


Como algo así como un combo de las respuestas de Caleb y Matt, lo hice:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) { self.checkVC = segue.destinationViewController; } }

... donde checkVC es una propiedad en el controlador de contenedor:

@property (weak,nonatomic) PXPCheckViewController * checkVC;

Solo tiene que configurar la Storyboard ID su transición embed a lo que desee (en este caso, cpdc_check_embed ):

... y luego verifique el identificador en -prepareForSegue:sender:

Todavía no es una salida, pero es más limpio que el de Matt (en mi humilde opinión) y más específico que el de Caleb, y todavía obtienes un guión gráfico atractivo:


El guión gráfico trata muy bien con los controladores de vista de contenedor incorporados, mostrando los segmentos a los controladores de vista raíz / secundarios para que las relaciones se muestren claramente. También es bueno cómo los controles padre e hijos se dividen en diferentes escenas.

Si desea lograr este efecto en su propio proyecto, entonces hay un truco que no es perfecto, pero muy sencillo. En mi ejemplo, supongamos que tengo un controlador de vista de contenedor que actúa como un controlador de barra de pestañas con solo dos pestañas, ''izquierda'' y ''derecha''. Quiero que una escena represente el controlador de vista padre, y dos escenas separadas representen el controlador de vista secundario ''izquierdo'' y el controlador de vista infantil ''derecho''.

Aunque es imposible, sería bueno si pudiera crear IBOutlet desde el controlador de vista de contenedor a sus hijos en diferentes escenas, y luego cuando se muestre el controlador de vista de contenedor configure las relaciones padre / hijo de acuerdo con las reglas descritas. Documentación de UIViewController . Si tuviéramos referencias a nuestros controladores de vista infantil ''izquierdo'' y ''correcto'', entonces podríamos establecer las relaciones sin problemas.

La solución estándar para este problema de referencia es crear referencias a controladores de vista secundarios arrastrando en las salidas de Object en la escena del controlador de vista de contenedor y luego especificando su tipo de clase como instancias de las clases de controlador de vista secundaria.

Sin embargo, para mantener a los niños separados en diferentes escenas, como los contenedores integrados de Apple, utilizaremos un truco diferente. En primer lugar, supongamos que tenemos las siguientes propiedades declaradas en nuestra clase de contenedor, ContainerViewController :

@property (nonatomic, strong, readwrite) UIViewController *leftViewController; @property (nonatomic, strong, readwrite) UIViewController *rightViewController;

En nuestro guión gráfico, seleccione la escena que representa el controlador de vista ''izquierda''. En el inspector de atributos, establezca la propiedad del identifier del controlador de vista en "cvc_leftViewController" ("cvc_" se refiere a ContainerViewController , pero realmente el identificador puede ser lo que usted desee). Haga lo mismo con la escena del controlador de vista derecha, estableciendo su identificador en "cvc_rightViewController" .

Ahora inserte el siguiente código en el método viewDidLoad ContainerViewController :

if (self.storyboard) { _leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"]; _rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"]; }

Cuando ContainerViewController se carga desde el guión gráfico, tomará los controladores de vista "izquierda" y "derecha" de sus respectivas escenas y establecerá referencias a ellos a través de sus propiedades. Ahora que tiene el control de las instancias de controlador de vista secundaria, puede establecer las relaciones padre / hijo como desee. Para aprender cómo hacerlo correctamente, consulte la documentación de UIViewController .

Este truco no es perfecto, y tiene muchas salvedades, pero si tiene cuidado puede hacerlo funcionar bien para su proyecto.

Editar: Aunque esto es completamente innecesario y no significa nada, si realmente quieres que el guión gráfico muestre las conexiones desde tu contenedor a tus controladores de vista infantil como los contenedores integrados de Apple, solo usa mi método anterior y luego configúralo pasa directamente de la escena del contenedor a las escenas secundarias, y simplemente nunca realiza esos segmentos. Ahora todo funcionará correctamente y se verá bonito también.


El problema con la respuesta de @ Ben (de lo contrario, razonable) es que solo funciona en un nivel de anidación. Más allá de eso, se requeriría que cada VC subsiguiente se personalice para guardar el controlador de vista anidada en prepareForSegue.

Para resolver esto, pasé demasiado tiempo explorando un índice basado en NSObject que podría agregar al Storyboard, enlazar a una escena y que luego registraría su VC padre en un índice global, basado en type y restorationId. Eso funciona / puede funcionar, pero es demasiado esfuerzo al final, y aún requiere el proceso de dos pasos de vinculación visual y búsqueda de programación.

Para mí, la solución más simple y general es descender lentamente la jerarquía del controlador de vista

En mi proyecto de prueba simple, agregué las siguientes líneas para viewDidLoad:

self.left.data = [ "Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.", "De carne lumbering animata corpora quaeritis." ]

donde a la left se define como:

lazy var left:CollectionViewController = { [unowned self] in return self.childViewControllerWithId("Left") as! CollectionViewController }()

y childViewControllerWithId se define como:

extension UIViewController { func childViewControllerWithId(rid:String) -> UIViewController? { // check immediate child controllers for vc in self.childViewControllers as! [UIViewController] { if vc.restorationIdentifier == rid { return vc } } // check nested controllers for vc in self.childViewControllers as! [UIViewController] { if let vc = vc.childViewControllerWithId(rid) { return vc } } assert(false, "check your assumptions") return nil } }

Tenga en cuenta que puede hacer otras variantes de find según el tipo, si es necesario. También tenga en cuenta que lo anterior requiere que defina la ID de restauración en el archivo Storyboard. Si no tiene instancias repetidas del mismo controlador de vista, entonces usar el tipo sería más fácil.

Y para expresar lo que es, con suerte, obvio, no necesita implementar prepareForSegue, ni tiene que usar la carga diferida, solo tiene que llamar a find(...) .