life containerview container change ios swift uiviewcontroller

ios - containerview - Agregar un controlador de vista como una subvista en otro controlador de vista



navigation controller swift 4 (7)

Consulte también la documentación oficial sobre la implementación de un controlador de vista de contenedor personalizado:

https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html#//apple_ref/doc/uid/TP40007457-CH11-SW1

Esta documentación tiene información mucho más detallada para cada instrucción y también describe cómo agregar transiciones.

Traducido a Swift 3:

func cycleFromViewController(oldVC: UIViewController, newVC: UIViewController) { // Prepare the two view controllers for the change. oldVC.willMove(toParentViewController: nil) addChildViewController(newVC) // Get the start frame of the new view controller and the end frame // for the old view controller. Both rectangles are offscreen.r newVC.view.frame = view.frame.offsetBy(dx: view.frame.width, dy: 0) let endFrame = view.frame.offsetBy(dx: -view.frame.width, dy: 0) // Queue up the transition animation. self.transition(from: oldVC, to: newVC, duration: 0.25, animations: { newVC.view.frame = oldVC.view.frame oldVC.view.frame = endFrame }) { (_: Bool) in oldVC.removeFromParentViewController() newVC.didMove(toParentViewController: self) } }

He encontrado algunas publicaciones para este problema, pero ninguna de ellas resolvió mi problema.

Di como si hubiera ..

  1. ViewControllerA
  2. ViewControllerB

Intenté agregar ViewControllerB como una subvista en ViewControllerA, pero arroja un error como " fatal error: unexpectedly found nil while unwrapping an Optional value ".

Debajo está el código ...

ViewControllerA

var testVC: ViewControllerB = ViewControllerB(); override func viewDidLoad() { super.viewDidLoad() self.testVC.view.frame = CGRectMake(0, 0, 350, 450); self.view.addSubview(testVC.view); // Do any additional setup after loading the view. }

ViewControllerB es solo una pantalla simple con una etiqueta.

ViewControllerB

@IBOutlet weak var test: UILabel! override func viewDidLoad() { super.viewDidLoad() test.text = "Success" // Throws ERROR here "fatal error: unexpectedly found nil while unwrapping an Optional value" }

EDITAR

Con la solución sugerida por las respuestas del usuario, ViewControllerB en ViewControllerA está desapareciendo de la pantalla. El borde gris es el marco que he creado para la subvista.


Gracias a Rob Agregar sintaxis detallada para su segunda observación:

let controller:MyView = self.storyboard!.instantiateViewControllerWithIdentifier("MyView") as! MyView controller.ANYPROPERTY=THEVALUE // If you want to pass value controller.view.frame = self.view.bounds; controller.willMoveToParentViewController(self) self.view.addSubview(controller.view) self.addChildViewController(controller) controller.didMoveToParentViewController(self)

Y para eliminar el viewcontroller:

self.willMoveToParentViewController(nil) self.view.removeFromSuperview() self.removeFromParentViewController()


Gracias a Rob, sintaxis actualizada de Swift 4.2

let controller:WalletView = self.storyboard!.instantiateViewController(withIdentifier: "MyView") as! WalletView controller.view.frame = self.view.bounds; controller.willMove(toParent: self) self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self)


Para Agregar y quitar ViewController

var secondViewController :SecondViewController? // Adding func add_ViewController() { let controller = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController")as! SecondViewController controller.view.frame = self.view.bounds; controller.willMove(toParent: self) self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self) self.secondViewController = controller } // Removing func remove_ViewController(secondViewController:SecondViewController?) { if secondViewController != nil { if self.view.subviews.contains(secondViewController!.view) { secondViewController!.view.removeFromSuperview() } } }


Un par de observaciones:

  1. Cuando crea una instancia del segundo controlador de vista, está llamando a ViewControllerB() . Si ese controlador de vista crea programáticamente su vista (lo cual es inusual), estaría bien. Pero la presencia de IBOutlet sugiere que la escena de este segundo controlador de vista se definió en Interface Builder, pero al llamar a ViewControllerB() , no le está dando al guión gráfico la oportunidad de instanciar esa escena y conectar todos los puntos de venta. Por lo tanto, el UILabel envuelto implícitamente es nil , lo que da como resultado su mensaje de error.

    En su lugar, desea darle a su controlador de vista de destino una "identificación del guión gráfico" en Interface Builder y luego puede usar instantiateViewController(withIdentifier:) para instanciarlo (y conectar todos los puntos de venta IB). En Swift 3:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")

    Ahora puede acceder a la vista de este controller .

  2. Pero si realmente desea addSubview (es decir, no está haciendo la transición a la siguiente escena), entonces está participando en una práctica llamada "contención del controlador de vista". No solo desea addSubview simplemente addSubview . Desea hacer algunas llamadas adicionales del controlador de vista de contenedor, por ejemplo:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id") addChild(controller) controller.view.frame = ... // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview view.addSubview(controller.view) controller.didMove(toParent: self)

    Para obtener más información acerca de por qué este addChild (anteriormente llamado addChildViewController ) y didMove(toParent:) (anteriormente llamado didMove(toParentViewController:) ) son necesarios, vea el video # 102 de WWDC 2011 - Implementación de UIViewController Containment . En resumen, debe asegurarse de que la jerarquía de su controlador de vista permanezca sincronizada con su jerarquía de vista, y estas llamadas a addChild y didMove(toParent:) aseguran que este sea el caso.

    Consulte también Creación de controladores de vista de contenedor personalizados en la Guía de programación del controlador de vista.

Por cierto, lo anterior ilustra cómo hacer esto mediante programación. En realidad, es mucho más fácil si usa la "vista de contenedor" en Interface Builder.

Entonces no tiene que preocuparse por ninguna de estas llamadas relacionadas con la contención, e Interface Builder se encargará de usted.

Para la implementación de Swift 2, consulte la revisión anterior de esta respuesta .


func callForMenuView () {

if(!isOpen) { isOpen = true let menuVC : MenuViewController = self.storyboard!.instantiateViewController(withIdentifier: "menu") as! MenuViewController self.view.addSubview(menuVC.view) self.addChildViewController(menuVC) menuVC.view.layoutIfNeeded() menuVC.view.frame=CGRect(x: 0 - UIScreen.main.bounds.size.width, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height); UIView.animate(withDuration: 0.3, animations: { () -> Void in menuVC.view.frame=CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width-90, height: UIScreen.main.bounds.size.height); }, completion:nil) }else if(isOpen) { isOpen = false let viewMenuBack : UIView = view.subviews.last! UIView.animate(withDuration: 0.3, animations: { () -> Void in var frameMenu : CGRect = viewMenuBack.frame frameMenu.origin.x = -1 * UIScreen.main.bounds.size.width viewMenuBack.frame = frameMenu viewMenuBack.layoutIfNeeded() viewMenuBack.backgroundColor = UIColor.clear }, completion: { (finished) -> Void in viewMenuBack.removeFromSuperview() }) }


This code will work for Swift 4.2. let controller:SecondViewController = self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as! SecondViewController controller.view.frame = self.view.bounds; controller.willMove(toParent: self) self.view.addSubview(controller.view) self.addChild(controller) controller.didMove(toParent: self)