Navega entre ViewController de forma modal
Navega entre ViewController de forma modal

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.

SwiftBeta

Tabla de contenido

Navegacion Modal: Aprende a navegar entre diferentes ViewController en UIKit

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.

Ejemplo de navegación modal en iOS
Ejemplo de navegación modal en iOS

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),
        ])
    }
}
View Controller con un UIButton

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
    }
}
View Controller B con una vista en blanco

Ahora volvemos a nuestro ViewControllerA y creamos el método que hará que se presente el ViewControllerB:

    func startNavigation() {
        self.present(ViewControllerB(), animated: true)
    }
Presentamos ViewControllerB con el método present de UIKit

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)
    }
}
Usamos dismiss para dismissear un ViewController usando UIKit

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)
    }
}
Creamos un ViewController nuevo para presenter en la jerarquía de vistas

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)
    }
}
Modificamos ViewControllerB para presentar ViewControllerC

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.

Si quieres seguir aprendiendo sobre SwiftUI, Swift, Xcode, o cualquier tema relacionado con el ecosistema Apple