
Navegación en UIKit: Modales
Aprende a cómo navegar entre diferentes ViewController usando la navegación modal de iOS con el Framework UIKit. Básicamente presentar de forma modal es presentar un ViewController por encima de otro ViewController. El propio ViewController es el encargado de presentar otro ViewController.
Tabla de contenido

Hoy en SwiftBeta vamos a ver a cómo navegar entre distintas pantallas de nuestra app. Vamos a ver los modales, que no es más que presentar un ViewController por encima de otro, mostrando al user una nueva vista de nuestra app. Este tipo de presentación es muy utilizada en iOS, desde apps nativas del propio iOS hasta apps creadas por developers.

Creamos el proyecto en Xcode
Lo primero de todo que vamos hacer es crear el proyecto en Xcode. Acuérdate que estamos usando UIKit, es por eso que debes seleccionar Storyboard en Interface.
Una vez hemos creado el proyecto nos vamos al ViewController. Allí lo vamos a renombrar, vamos a llamarlo ViewControllerA, de esta manera será más fácil entender el post de hoy. Una vez renombrado nos tenemos que ir a nuestro Storyboard y cambiar la clase y módulo de nuestro ViewController.
Volvemos a nuestro ViewControllerA, y vamos a añadir un UIButton y lo centramos en la vista de ViewController
import UIKit
class ViewControllerA: UIViewController {
private lazy var swiftBetaButton: UIButton = {
var configuration = UIButton.Configuration.bordered()
configuration.title = "Present View Controller A"
let button = UIButton(type: .system, primaryAction: UIAction(handler: { _ in
self.startNavigation()
}))
button.configuration = configuration
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
view.addSubview(swiftBetaButton)
NSLayoutConstraint.activate([
swiftBetaButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
swiftBetaButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
Cuando el user pulse el UIButton, se llamará al método startNavigation, y este método hará que se presente nuestro ViewControllerB. Y es justo lo que vamos hacer antes de crear la función startNavigation, vamos a crear nuestro ViewControllerB.
Va a ser muy sencillo, creamos el siguiente fichero con este código:
import UIKit
class ViewControllerB: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
}
}
Ahora volvemos a nuestro ViewControllerA y creamos el método que hará que se presente el ViewControllerB:
func startNavigation() {
self.present(ViewControllerB(), animated: true)
}
Si compilamos, y probamos nuestra app vemos que al apretar el UIButton nos aparece el ViewControllerB 👏
Y te preguntarás, una vez presentado cómo podemos dismissear ViewControllerB? tan solo necesitamos hacer swiper hacía abajo y ViewControllerB desaparecerá. Pero, podemos añadir un UIButton dejando explicitamente que al apretar ese UIButton el ViewControllerB desaparecerá.
import UIKit
class ViewControllerB: UIViewController {
private lazy var dismissButton: UIButton = {
var configuration = UIButton.Configuration.bordered()
configuration.title = "Dismiss View Controller B"
let button = UIButton(type: .system, primaryAction: UIAction(handler: { _ in
self.dimissViewControllerB()
}))
button.configuration = configuration
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(dismissButton)
NSLayoutConstraint.activate([
dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
dismissButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
func dimissViewControllerB() {
self.dismiss(animated: true)
}
}
Cuando se pulsa el único UIButton de nuestro ViewControllerB, se llama al método del ViewController dismiss. De esta manera al apretar el UIButton nuestro ViewControllerB se dismissea y desaparece de la jerarquía de vistas.
Podríamos llamar al métodos dismiss con completionBlock para realizar alguna acción cuando el ViewControllerB desaparece.
¡Vamos a continuar!
Para finalizar el post de hoy vamos a crear un ViewControllerC
import UIKit
class ViewControllerC: UIViewController {
private lazy var dismissButton: UIButton = {
var configuration = UIButton.Configuration.bordered()
configuration.title = "Dismiss View Controller B"
let button = UIButton(type: .system, primaryAction: UIAction(handler: { _ in
self.dimissViewControllerB()
}))
button.configuration = configuration
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
view.addSubview(dismissButton)
NSLayoutConstraint.activate([
dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
dismissButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
func dimissViewControllerB() {
self.dismiss(animated: true)
}
}
Ahora, desde el ViewControllerB, vamos a crear un UIButton para poder presentar UIViewControllerC, aparte de crearlo lo añadimos a la vista con sus constraints y su método para presentar ViewControllerC:
import UIKit
class ViewControllerB: UIViewController {
private lazy var dismissButton: UIButton = {
var configuration = UIButton.Configuration.bordered()
configuration.title = "Dismiss View Controller B"
let button = UIButton(type: .system, primaryAction: UIAction(handler: { _ in
self.dimissViewControllerB()
}))
button.configuration = configuration
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private lazy var swiftBetaButton: UIButton = {
var configuration = UIButton.Configuration.bordered()
configuration.title = "Present View Controller C"
let button = UIButton(type: .system, primaryAction: UIAction(handler: { _ in
self.startNavigation()
}))
button.configuration = configuration
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(dismissButton)
view.addSubview(swiftBetaButton)
NSLayoutConstraint.activate([
dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
dismissButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
swiftBetaButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
swiftBetaButton.bottomAnchor.constraint(equalTo: dismissButton.topAnchor, constant: -32),
])
}
func dimissViewControllerB() {
self.dismiss(animated: true)
}
func startNavigation() {
self.present(ViewControllerC(), animated: true)
}
}
Ahora si compilamos podemos ir navegando entre estas 3 vistas.
Conclusión
Hoy hemos aprendido a cómo presentar un UIViewController de forma modal. En el siguiente video aprenderemos a cómo pushear ViewController dentro de un UINavigationController.