Aprende a utilizar la navegación push con UINavigationController
Aprende a utilizar la navegación push con UINavigationController

Navegación en UIKit: UINavigationController Push

La navegación Push es muy útil y muy usada en iOS. Para hacerla necesitamos un UINavigationController y ir pusheando ViewControllers, de esta manera podremos ir añadiendo ViewControllers a nuestra jerarquía de vistas. Hoy aprendemos a cómo usar esta navegación que te servirá para crear tus apps.

SwiftBeta

Tabla de contenido

Aprende a usar la Navegación Push en UIKit con UINavigationController

Hoy en SwiftBeta vamos a ver otra manera para poder navegar de un View Controller a otro. Dentro de iOS es muy común la navegación push, esta consiste en navegar de un ViewController a otro como el gif que muestro acontinuación.

Ejemplo de presentación Push en iOS
Ejemplo de presentación Push en iOS

Este tipo de navegación lo vemos en aplicaciones del propio sistema operativo. En el anterior posts vimos a cómo presentar un ViewController usando modales, básicamente es presentar un ViewController dentro de otro, pero hoy vamos a ver un nuevo Controller llamado UINavigationController. Este NavigationController va a ser la base de nuestra navegación, y lo que haremos será llamar a este controller para poder pushear ViewControllers en la jerarquía de vistas. Solo vamos a tener un UINavigationController, y en lugar de decirle al ViewController que presente otro ViewController, esta tarea se la vamos a delegar al UINavigationController. Y lo que hará el NaviegationController es ir añadiendo ViewControllers a nuestra jerarquía de vistas, será como un Stack. No te preocupes que es super sencillo y lo ¡vamos a verlo paso a paso!

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 Storyboard. Allí vamos a añadir un NavigationController a nuestro ViewController. Para hacerlo seleccionamos el ViewController y nos vamos al menu, allí seleccionamos Editor -> Embed in -> NavigationController

Añader un UINavigationController a la jerarquía de vistas de tu app
Añader un UINavigationController a la jerarquía de vistas de tu app

Fíjate que se ha añadido una nueva vista a tu Storyboard, esta vista es el UINavigationController

UINavigationController añadido correctamente con Storyboard
UINavigationController añadido correctamente con Storyboard

Lo siguiente que vamos hacer es renombrar ViewController a ViewControllerA, y para ello debemos modificar nuestro ViewController dentro del Storyboard y también renombrar la clase ViewController a ViewControllerA:

import UIKit

class ViewControllerA: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view.backgroundColor = .green
    }
}
Creamos nuestro primer UIViewController con Swift

Lo siguiente que vamos hacer es:

  • Añadir un title a nuestro ViewController, al añadir un título aparecerá en el NavigationController
  • Añadir un UIBarButtonItem a nuestro UINavigationController. Al pulsar este nuevo Button le diremos al UINavigationController que haga push de un nuevo UIViewController.
import UIKit

class ViewControllerA: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .green
        title = "View Controller A"
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next",
                                                                 style: .done,
                                                                 target: self,
                                                                 action: #selector(nextViewController))
    }
    
    @objc
    private func nextViewController() {
        print("Presenta View Controller B")
    }
}
Creamos un UIBarButtonItem en nuestro UINavigationController

Ahora debemos crear un nuevo ViewController, lo vamos a llamar ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white
        title = "View Controller B"
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next",
                                                                 style: .done,
                                                                 target: self,
                                                                 action: #selector(nextViewController))
    }
    
    @objc
    private func nextViewController() {
        print("Presenta View Controller C")
    }
}
Creamos el ViewControllerB

Una vez creado ViewControllerB, volvemos a ViewControllerA y rellenamos el método nextViewController:

    @objc
    private func nextViewController() {
        self.navigationController?.pushViewController(ViewControllerB(),
                                                      animated: true)
    }
Método para navegar de ViewControllerA a ViewControllerB

Si compilamos podemos ver que:

  • Al pulsar el button Next, se pushea el ViewControllerB
  • Al presentarse ViewControllerB aparece un button en la parte izquierda del UINavigationController, si lo pulsamos volvemos al ViewControllerA
  • Desde ViewControllerB, tenemos el efecto de arrastrar y ver la transición de cómo volvemos a ViewControllerA (esto viene completamente gratis al hacer push de un ViewController desde un UINavigationController).

Lo siguiente que vamos hacer es crear un ViewControllerC, y desde allí vamos a presentar ViewControllerD, utilizaremos lo que aprendimos en el anterior post de presentar modales.

De momento, nuestro ViewControllerC va a tener el siguiente código:

import UIKit

class ViewControllerC: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .orange
        title = "View Controller C"
    }
}
Creamos ViewControllerC

Una vez creado volvemos a ViewControllerB para que cuando el user pulse el Button del NavigationBar, se muestra el ViewControllerC

    @objc
    private func nextViewController() {
        self.navigationController?.pushViewController(ViewControllerC(),
                                                      animated: true)
    }
Método para navegar de ViewControllerB a ViewControllerC

Compilamos y probamos que todo funciona bien. Una vez comprobado, vamos a añadir un UIButton a nuestro ViewControllerC, al apretar este UIButton se mostrará el ViewControllerD (que aún no hemos creado, lo haremos cuando añadamos el UIButton a ViewControllerC).

import UIKit

class ViewControllerC: UIViewController {
    
    private lazy var swiftBetaButton: UIButton = {
        var configuration = UIButton.Configuration.bordered()
        configuration.title = "¡Suscríbete a SwiftBeta!"
        
        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 = .orange
        view.addSubview(swiftBetaButton)
        title = "View Controller C"
        
        NSLayoutConstraint.activate([
            swiftBetaButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            swiftBetaButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])
    }

    func startNavigation() {
        self.present(ViewControllerD(), animated: true)
    }
}
Desde ViewControllerC vamos a presentar ViewControllerD de forma modal

Al añadir el siguiente código, tendremos un error. Se queja que no hemos creado ViewControllerD y por lo tanto no sabe como crear una instancia. Así que, vamos a crearlo (no nos vamos a complicar y va a ser muy sencillo):

import UIKit

class ViewControllerD: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .purple
    }
}
Creamos ViewControllerD

Si compilamos, vamos a ver la navegación que hemos creado. Podemos pushear 2 View Controllers. De A pusheamos B, y de B pusheamos C, y una vez que estamos en C presentamos el modal D. Nosotros aquí ahora podríamos rellenar las vistas del ViewController con las subvistas que quisieramos: UIButtons, UILabel, UITableView, UICollectionView, etc.

Hemos visto cómo pushear un ViewController dentro de un UINavigationController, pero también podemos hacer pop. Esto es muy parecido a present y dismiss de los modales.

Pop ViewController

Imagina que en tu UINavigationController has hecho push de varios ViewControllers, en lugar de ir pulsando el button de back para volver a la pantalla inicial, lo que se puede hacer es usar el método popToRootViewController(animated:) este método sirve para volver al root view controller de tu jerarquía de vistas. Vamos a probarlo con el código que hemos creado. Nos vamos al ViewControllerC y en lugar de que al pulsar el Button aparezca el modal del ViewControllerD, lo que vamos hacer es que navegue directamente a ViewControllerA, y para hacerlo solo necesitmos una línea de código:

    func startNavigation() {
//        self.present(ViewControllerD(), animated: true)
        self.navigationController?.popToRootViewController(animated: true)
    }

Si compilamos, y navegamos hasta ViewControllerC, al apretar el UIButton volvemos automáticamente hasta ViewControllerA, ¡sin pasar por ViewControllerB! esto es muy útil para romper flows de navegación. También, otro detalle curioso es que en lugar de que el user pulsara el Button back que se crea automatícamente al añadir un UINavigationController, podríamos añadir la acción del back en cualquier otro button de nuestra vista. Vamos a volver modificar el método de starNavigation() y vamos a simular el código que realiza el button back.

func startNavigation() {
//        self.present(ViewControllerD(), animated: true)
        self.navigationController?.popViewController(animated: true)
    }

Si lo probamos, vemos cómo al apretar el UIButton volvemos al ViewController anterior. ¿Sencillo verdad? cuando programamos esta navegación es muy simple customizar las acciones que queremos realizar.

Conclusión

Hoy hemos aprendido otra manera de tener una navegación dentro de nuestra aplicación iOS. En lugar de presentar desde un UIViewController, lo que hacemos es presentar ViewControllers desde un componente nuevo llamado UINavigationController. Esta manera de presentar ViewControllers es muy común dentro de iOS.

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