youtubers tesis sobre sirve resumida que para investigaciones investigacion historia caracteristicas ios cocoa-touch subview uicontainerview childviewcontroller

ios - tesis - Cómo agregar una vista de contenedor mediante programación



tesis sobre youtube pdf (4)

Detalles

  • Xcode 10.2 (10E125), Swift 5

Solución

import UIKit class WeakObject { weak var object: AnyObject? init(object: AnyObject) { self.object = object} } class EmbedController { private weak var rootViewController: UIViewController? private var controllers = [WeakObject]() init (rootViewController: UIViewController) { self.rootViewController = rootViewController } func append(viewController: UIViewController) { guard let rootViewController = rootViewController else { return } controllers.append(WeakObject(object: viewController)) rootViewController.addChild(viewController) rootViewController.view.addSubview(viewController.view) } deinit { if rootViewController == nil || controllers.isEmpty { return } for controller in controllers { if let controller = controller.object { controller.view.removeFromSuperview() controller.removeFromParent() } } controllers.removeAll() } }

Uso

class SampleViewController: UIViewController { private var embedController: EmbedController? override func viewDidLoad() { super.viewDidLoad() embedController = EmbedController(rootViewController: self) let newViewController = ViewControllerWithButton() newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 150), size: CGSize(width: 200, height: 80)) newViewController.view.backgroundColor = .lightGray embedController?.append(viewController: newViewController) } }

Muestra completa

ViewController

import UIKit class ViewController: UIViewController { private var embedController: EmbedController? private var button: UIButton? private let addEmbedButtonTitle = "Add embed" override func viewDidLoad() { super.viewDidLoad() button = UIButton(frame: CGRect(x: 50, y: 50, width: 150, height: 20)) button?.setTitle(addEmbedButtonTitle, for: .normal) button?.setTitleColor(.black, for: .normal) button?.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) view.addSubview(button!) print("viewDidLoad") printChildViewControllesInfo() } func addChildViewControllers() { var newViewController = ViewControllerWithButton() newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 150), size: CGSize(width: 200, height: 80)) newViewController.view.backgroundColor = .lightGray embedController?.append(viewController: newViewController) newViewController = ViewControllerWithButton() newViewController.view.frame = CGRect(origin: CGPoint(x: 50, y: 250), size: CGSize(width: 200, height: 80)) newViewController.view.backgroundColor = .blue embedController?.append(viewController: newViewController) print("/nChildViewControllers added") printChildViewControllesInfo() } @objc func buttonTapped() { if embedController == nil { embedController = EmbedController(rootViewController: self) button?.setTitle("Remove embed", for: .normal) addChildViewControllers() } else { embedController = nil print("/nChildViewControllers removed") printChildViewControllesInfo() button?.setTitle(addEmbedButtonTitle, for: .normal) } } func printChildViewControllesInfo() { print("view.subviews.count: /(view.subviews.count)") print("childViewControllers.count: /(childViewControllers.count)") } }

ViewControllerWithButton

import UIKit class ViewControllerWithButton:UIViewController { override func viewDidLoad() { super.viewDidLoad() } private func addButon() { let buttonWidth: CGFloat = 150 let buttonHeight: CGFloat = 20 let frame = CGRect(x: (view.frame.width-buttonWidth)/2, y: (view.frame.height-buttonHeight)/2, width: buttonWidth, height: buttonHeight) let button = UIButton(frame: frame) button.setTitle("Button", for: .normal) button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) view.addSubview(button) } override func viewWillLayoutSubviews() { addButon() } @objc func buttonTapped() { print("Button tapped in /(self)") } }

Resultados

Una vista de contenedor se puede agregar fácilmente a un guión gráfico a través del editor de interfaz. Cuando se agrega, una vista de contenedor es una vista de marcador de posición, un segmento de inserción y un controlador de vista (secundario).

Sin embargo, no puedo encontrar una manera de agregar una vista de contenedor mediante programación. En realidad, ni siquiera puedo encontrar una clase llamada UIContainerView o menos.

Un nombre para la clase de Vista de contenedor es seguramente un buen comienzo. Una guía completa que incluye el segue será muy apreciada.

Conozco la Guía de programación de View Controller, pero no la considero igual que Interface Builder para Container Viewer. Por ejemplo, cuando las restricciones se establecen correctamente, la vista (secundaria) se adapta a los cambios de tamaño en la Vista de contenedor.


Aquí está mi código en swift 3, también funciona en swift 4.

class ViewEmbedder { class func embed( parent:UIViewController, container:UIView, child:UIViewController, previous:UIViewController?){ if let previous = previous { removeFromParent(vc: previous) } child.willMove(toParentViewController: parent) parent.addChildViewController(child) container.addSubview(child.view) child.didMove(toParentViewController: parent) let w = container.frame.size.width; let h = container.frame.size.height; child.view.frame = CGRect(x: 0, y: 0, width: w, height: h) } class func removeFromParent(vc:UIViewController){ vc.willMove(toParentViewController: nil) vc.view.removeFromSuperview() vc.removeFromParentViewController() } class func embed(withIdentifier id:String, parent:UIViewController, container:UIView, completion:((UIViewController)->Void)? = nil){ let vc = parent.storyboard!.instantiateViewController(withIdentifier: id) embed( parent: parent, container: container, child: vc, previous: parent.childViewControllers.first ) completion?(vc) } }

Uso

@IBOutlet weak var container:UIView! ViewEmbedder.embed( withIdentifier: "MyVC", // Storyboard ID parent: self, container: self.container){ vc in // do things when embed complete }

Use la otra función de incrustación con un controlador de vista sin guión gráfico.


La respuesta de @ Rob en Swift 3:

// add container let containerView = UIView() containerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(containerView) NSLayoutConstraint.activate([ containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10), containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10), ]) // add child view controller view to container let controller = storyboard!.instantiateViewController(withIdentifier: "Second") addChildViewController(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false containerView.addSubview(controller.view) NSLayoutConstraint.activate([ controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), controller.view.topAnchor.constraint(equalTo: containerView.topAnchor), controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) ]) controller.didMove(toParentViewController: self)


Una "vista de contenedor" del guión gráfico es solo un objeto estándar de UIView . No hay un tipo especial de "vista de contenedor". De hecho, si observa la jerarquía de vistas, puede ver que la "vista de contenedor" es una vista de UIView estándar:

Para lograr esto mediante programación, usted emplea "contención del controlador de vista":

  • Cree una instancia del controlador de vista secundario llamando a instantiateViewController(withIdentifier:) en el objeto del guión gráfico.
  • Llame a addChild en su controlador de vista principal.
  • Agregue la vista del controlador de view a su jerarquía de vistas con addSubview (y también configure el frame o las restricciones según corresponda).
  • Llame al didMove(toParent:) en el controlador de vista secundario, pasando la referencia al controlador de vista primario.

Consulte Implementación de un controlador de vista de contenedor en la Guía de programación del controlador de vista y la sección "Implementación de un controlador de vista de contenedor" de la Referencia de clase UIViewController .

Por ejemplo, en Swift 4.2 podría verse así:

override func viewDidLoad() { super.viewDidLoad() let controller = storyboard!.instantiateViewController(withIdentifier: "Second") addChild(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(controller.view) NSLayoutConstraint.activate([ controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), controller.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 10), controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10) ]) controller.didMove(toParent: self) }

Tenga en cuenta que lo anterior en realidad no agrega una "vista de contenedor" a la jerarquía. Si quieres hacer eso, harías algo como:

override func viewDidLoad() { super.viewDidLoad() // add container let containerView = UIView() containerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(containerView) NSLayoutConstraint.activate([ containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10), containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10), containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10), containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10), ]) // add child view controller view to container let controller = storyboard!.instantiateViewController(withIdentifier: "Second") addChild(controller) controller.view.translatesAutoresizingMaskIntoConstraints = false containerView.addSubview(controller.view) NSLayoutConstraint.activate([ controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), controller.view.topAnchor.constraint(equalTo: containerView.topAnchor), controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) ]) controller.didMove(toParent: self) }

Este último patrón es extremadamente útil si alguna vez hace la transición entre diferentes controladores de vista secundarios y solo desea asegurarse de que la vista de un niño esté en la misma ubicación y la vista del niño anterior (es decir, todas las restricciones únicas para la ubicación están dictadas por la vista del contenedor, en lugar de necesitar reconstruir estas restricciones cada vez). Pero si solo realiza una contención de vista simple, la necesidad de esta vista de contenedor separada es menos convincente.

En los ejemplos anteriores, estoy configurando translatesAutosizingMaskIntoConstraints a false definiendo las restricciones yo mismo. Obviamente, puede dejar las translatesAutosizingMaskIntoConstraints como true y establecer tanto el frame como la autosizingMask para las vistas que agregue, si lo prefiere.

Consulte las revisiones anteriores de esta respuesta para las versiones de Swift 3 y Swift 2 .