Aprende a usar los Xibs en UIKit
Aprende a usar los Xibs en UIKit

¿Cómo usar los XIBS en UIKit? (Interface Builder)

Los XIBs nos permiten crear la pantallas de nuestra app. Es una alternativa a los Storyboard y crear las vista directamente por código. Podemos crear vistas usando XIBs y nos beneficiamos de todas las ventajas de Interface Builder en Xcode

SwiftBeta

Tabla de contenido

Aprende a usar XIBs en UIKit

Hoy en SwiftBeta vamos a seguir con el curso de UIKit. Esta vez aprenderemos a crear vistas usando XIBS y crearemos navegación entre ellas. Hasta ahora, cuando hemos hablado de UIKit y de crear la vista, lo hemos hecho por código y usando los Storyboards. Hoy vamos a usar el Interface Builder, pero esta vez usaremos XIBS. Para darte un poco de contexto, los XIBs son anteriores a los Storyboards.

En el video de hoy vamos a ver otra manera de crear vistas en UIKit, vas a ver que es muy parecido al usar Storyboards, es decir es muy visual y también muchas de las cosas que vimos con los Storyboards pueden aplicarse exactamente igual en los XIBs, al final tenemos el Interface Builder con una serie de ventajas como video de diferentes devices, dark mode, inspector de atributos, etc.
Si te estás preguntando que significa XIBS, es un acrónimo de XML Interface Builder (aunque en algunos lados leeras que es por Xcode Interface Builder).
La gracia del video de hoy es que usaremos el Interface Builder para crear una vista, pudiendo ver los componentes visuales que vayamos añadiendo con sus constraints (Auto Layout). También aprenderemos a navegar entre dos ViewControllers creados con XIBS, Navegar de un ViewController del Storyboard a otro creado con XIB y a cómo inyectar vistas XIBs en ViewControllers (esto es realmente útil para reutilizar componentes), no te pierdas los detalles de este video, que vas a ver que es muy entretenido y didáctico.

Si quieres apoyar el canal y que siga creando este tipo de contenido, suscríbete. De esta manera seguiré subiendo un video cada semana.

Creamos proyecto en Xcode

Lo primero de todo que vamos hacer es crear un proyecto en Xcode. En este proyecto vamos a seleccionar como Interface UIKit

Como hemos dicho, el ejemplo práctico de hoy es aprender a usar Xibs en UIKit, lo que haremos será que una vez creado el proyecto. Crearemos un ViewController2

Creamos una vista con un XIB asociado

Para crear el ViewController2 pulsamos COMMAND+N. Aquí vamos a seleccionar Cocoa Touch Class y le vamos a dar el nombre de ViewController2. Muy importante marcar el checkbox de ✅ Also create XIB file

Creamos nuestro primer XIB con subclase UIViewController
Creamos nuestro primer XIB con subclase UIViewController

Una vez creado, en nuestro listado de ficheros ahora tenemos dos ficheros que se llaman ViewController2. Uno representa el código swift y el otro representa el XIB, es decir, la parte visual de nuestro ViewController. Fíjate, es como si estuvieramos en un Storyboard, pero solo se visualiza un único ViewController.

Dentro de este XIB vamos a añadir varias vistas, y vamos a aplicar algunas constraints con AutoLayout. Nos vamos a beneficiar del Interface Builder y de las ventajas que nos ofrece.

A continuación, vamos a añadir 2 vistas, una UIImageView y también un UIButton. Primero añadimos el UIImageView, podemos hacerlo de dos maneras:

  • Pulsamos el botón de + para que aparezca la librería de UIKit
  • Pulsamos el shortcut (atajo de teclado) COMMAND+ SHIFT + L

Una vez tenemos el UIImageView, lo añadimos a la parte superior de nuestra Vista y le damos un backgroundColor (de esta manera no tenemos que añadir ningún recurso a Xcode, cuando digo recurso me refiero a una imagen) para hacerlo, vamos al inspector de atributos y le damos un color cualquiera

Vamos a continuar, mientras está seleccionado el UIImageView, mantenemos la tecla control y añadimos 5 constraints:

  • Leading
  • Trailing
  • Top
  • Width
  • Height
Si queremos añadir varias constraints de golpe, podemos mantener pulsado SHIFT, de esta manera al marcar varias constraints no desaparece el menu.

Una vez hemos añadido las constrains, deberíamos tener algo parecido a la siguiente imagen:

Añadimos a nuestro XIB un UIImageView y añadimos Auto Layout con sus constraints
Añadimos a nuestro XIB un UIImageView y añadimos Auto Layout con sus constraints

Fíjate que al tener las constraints correctamente configuradas, aparecen en azul. Esto nos indica que hemos añadido las constrains necesarias para que la vista se sepa posicionar dentro de la View.

Ahora imagina que quiero amplicar el alto de mi UIImageView, al hacerlo, aparecen las constraints en naranja, esto significa que algo no va bien:

Al modificar las constraints vemos que aparecen en naranja, esto significa que hay que arreglarlas
Al modificar las constraints vemos que aparecen en naranja, esto significa que hay que arreglarlas

Podemos arreglarlo de varias formas, si queremos volver al estado anterior, es decir, deshacer el cambio del alto que acabo de hacer. Podemos ir a esta opción del Interface Builder

Interface Builder nos ofrece una serie de opciones para arreglar nuestras constraints
Interface Builder nos ofrece una serie de opciones para arreglar nuestras constraints

Al pulsar la primera opción, la vista se reajusta con las constraints que tiene. PERO ahora imagina que quieres realizar este cambio, para hacerlo puedes pulsar el siguiente button donde aparecen las siguientes opciones:

Escogemos Update Constraint Constants para arreglar nuestras constraints
Escogemos Update Constraint Constants para arreglar nuestras constraints

Si seleccionamos la primera, Update Constraint Constants las constraints se actualizan para que se adapten al alto que acabo de cambiar.

Ahora vamos a añadir un UIButton, este button nos servirá para navegar a otro ViewController. Para añadir el UIButton, abrímos la librería y buscamos un UIButton. Vamos a añadirlo justo debajo del UIImageView, y también vamos a crear constraints con Auto Layout

  • Leading
  • Trailing
  • Top (UIImageView)
  • Width
  • Height

El resultado que nos quedaría es el siguiente:

Añadimos un UIButton y añadimos también sus constraints
Añadimos un UIButton y añadimos también sus constraints

Fíjate que en el inspector de atributos puedes settear muchas propiedades del UIButton (y de cualquier otra subvista de nuestra view). Es muy importante que sepas que puedes customizar directamente la vista desde estas propiedades. Esta ventaja también la tenemos cuando usamos Storyboards, igual que poder rotar, cambiar device, o el panel que hemos visto de las constraints hace un momento.

Ahora lo que vamos hacer es ir a nuestro Storyboard. Y dentro del único ViewController que tenemos, vamos a añadir un UIButton. Este UIButton nos permitirá navegar al ViewController2 cuando lo pulsemos. Pues vamos a ello:

  • Añadimos el UIButton
  • Añadimos constraints (top, center vertically, width y height)
  • Creamos el @IBAction en la clase ViewController
Conectamos el UIButton del Storyboard con nuestro código del ViewController
Conectamos el UIButton del Storyboard con nuestro código del ViewController

Una vez creado el método, vamos a añadir la lógica para mostrar nuestro ViewController2.

Si añadimos el siguiente código y compilamos, vamos a ver qué ocurre:

    @IBAction func didTapOnButton(_ sender: Any) {
        let viewController2 = ViewController2()
        self.present(viewController2,
                     animated: true)
    }
Método que añadimos para presentar nuestro ViewController2 (spoiler, no funcionará)

Al probar la navegación en nuestro simulador, vemos que no se presenta nuestro ViewController2, el que tenemos creado con un XIB. Esto es porque tenemos que utilizar otro inicializador,

Debemos utilizar el siguiente código:

    @IBAction func didTapOnButton(_ sender: Any) {
        let viewController2 = ViewController2(nibName: "ViewController2",
                                              bundle: nil)
        self.present(viewController2,
                     animated: true)
    }
Añadimos el código correcto para navegar al ViewController2
Como detalle curioso verás que en el inicializador, estamos usando nibName en lugar de xibName. Hay que diferenciar entre XIB y NIB, XIB es el XML y NIB es lo que se genera al compilar el XIB. Digamos que para nosotros los developers es fácil trabajar con XML y para nuestra máquina es más fácil trabajar con NIBs. Esto lo repetiré más adelante, pero cuando nosotros trabajamos con una vista en el Interface Builder, en ese momento hablamos de XIBs, y cuando queremos usar los XIBS por código, ahí verás que usamos NIBs (más adelante te quedará más claro, por que lo vamos a ver). Por cierto NIBs es un acrónimo de NeXTSTEP Interface Builder, detalle

Si ahora compilamos y probamos nuestra app, vemos que funciona perfectamente. Acabamos de aprender a usar los XIBs para presentar UIViewControllers. Pero vamos a continuar, vamos a seguir viendo qué podemos hacer con los XIBS.

Cargar XIB de un UIView dentro de un XIB de un UIViewController

Al crear nuestro ViewController2, en el proceso de creación hemos podido crear el XIB y la clase a la vez. Pero, también podemos hacer el mismo proceso con las vistas. Nosotros podemos crear una view y tener su xib. Y podemos usar esta vista en diferentes ViewControllers. Esto es muy útil, un cambio en esa vista se modificaría en todos los sitios donde la estemos utilizando. Y esto es lo que vamos a ver ahora. Vamos a crear una View que se utilizará en nuestro XIB y también en nuestro Storyboard.

Vamos a empezar creando una CustomView que sea de subclase UIView y una vez creado vamos a crear un XIB.

Creamos nuestra CustomView, fíjate que al hacerlo, no podemos marcar que cree también el XIB file, pero no te preocupes que lo crearemos justo después, a mano. Así aprendes una cosa nueva

Creamos una UIView llamada CustomView
Creamos una UIView llamada CustomView

Ahora vamos a crear el XIB file, para hacerlo, vamos al listado de ficheros y pulsamos COMMAND+N. Aquí seleccionamos un nuevo tipo que no habíamos visto hasta ahora.

Creamos el XIB que estará asociado a CustomView
Creamos el XIB que estará asociado a CustomView

Al hacerlo, le damos un nombre. Lo vamos a llamar igual CustomView.

Si abrimos el XIB de CustomView, vemos que dentro aparece una View vacía, y que tiene la forma de un iPhone, pero podemos cambiar este aspecto desde el inspector de atributos y decirle que su tamaño sea freeform.

Modificamos el tamaño de nuestro CustomView
Modificamos el tamaño de nuestro CustomView

Al hacerlo podemos modificar el tamaño, en mi caso lo voy a dejar con la forma de un rectángulo. Y a continuación voy a añadir un UILabel.

Nuestro CustomView tiene un UILabel y está centrado verticalmente y horizontalmente
Nuestro CustomView tiene un UILabel y está centrado verticalmente y horizontalmente

Y el UILabel lo voy a centrar en los ejes vertical y horizontal. También voy a cambiar el backgroundColor a orange. Vamos a realizar un último paso en nuestro XIB antes de ir al código. Vamos a ir al File's owner y vamos a asignarle la clase CustomView que acabamos de crear:

Sección Placeholders, File's Owner
Sección Placeholders, File's Owner

Una vez seleccionado, vamos al inspector de atributos. Y ahí vamos a la sección de identity inspector.

Añadimos CustomView a la clase del File's Owner
Añadimos CustomView a la clase del File's Owner 

Esto lo hacemos ya que la instancia de este File's Owner, que en este caso es la clase CustomView, va a ser la responsable de desarchivar e instanciar nuestro NIB (recuerda que ahora estamos tocando código, ahora hablamos de NIBs), ¿y cómo lo vamos hacer? Vamos a verlo paso por paso en nuestra clase CustomView, vamos a añadir muy pocas pero necesarias líneas de código.

Para poder utilizar esta vista CustomView dentro de un XIB o el Storyboard, debemos añadir el siguiente código:

class CustomView: UIView {
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
}
Método para inicializar un XIB desde Xcode

Este inicializador lo necesitamos por el mero hecho de usar el Interface Builder. Cuando este inicializador se llama, tenemos que añadir unas cuantas líneas para tener nuestra Vista preparada. Vamos a verlo paso a paso:

func setup() {
        let nib = UINib(nibName: "CustomView", bundle: nil)	// 1
        guard let customView = nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error instantiating CustomView") } // 2
        addSubview(customView) // 3
    }
Configuramos nuestro XIB -> NIB para cargarlo en la jerarquía de vistas
  1. Preparamos nuestro NIB para ser desarchivado e instanciado. Si no añadimos el nombre de nuestro NIB correctamente, obtendremos un error cuando abramos la aplicación. Hay que ir con cuidado de añadir el nombre correcto.
  2. Desarchivamos e instanciamos el contenido de nuestro NIB, también aprovechamos y casteamos a UIView (el resultado que obtenemos es un Array, nosotros nos quedamos con la primera posición y verificamos que ese elemento sea de tipo UIView)
  3. Si todo va bien, añadimos la View a la jerarquía de vistas
Un tip, cuando nosotros trabajamos desde el Interface Builder y modificamos la vista, estamos modificando el XIB, pero cuando entramos al código, ahí verás que todo hace referencia a los NIBs

Ya hemos añadido todo el código necesario. Ahora nos vamos a nuestro XIB del ViewController2. Aquí vamos a añadir una UIView, justo debajo del UIButton y añadimos las constraints necesarias:

Añadimos un UIView a nuestro XIB ViewController2 para usar la vista XIB CustomView
Añadimos un UIView a nuestro XIB ViewController2 para usar la vista XIB CustomView

Ahora, para cargar la vista CustomView, tan solo debemos ir a nuestro inspector de identidad:

La UIView que acabamos de añadir le asignamos la clase CustomView
La UIView que acabamos de añadir le asignamos la clase CustomView

Y añadir que la Custom Class es CustomView. Si compilamos nuestra app, vamos a ver si ha funcionado:

Al probarlo en el simulador, aparece correctamente la vista XIB dentro del ViewController2
Al probarlo en el simulador, aparece correctamente la vista XIB dentro del ViewController2

Perfecto, aparece nuestra vista CustomView mostrando su contenido, el backgroundColor y UILabel.

Podríamos hacer exactamente lo mismo, para cargar esta vista CustomView dentro del Storyboard. Es decir, acabamos de cargar un XIB que era un UIView en otro XIB que era un UIViewController. Ahora lo que vamos hacer es cargar la Custom View en un ViewController pero de nuestro Storyboard.

Cargar XIB de un UIView en un Storyboard

Nos vamos a nuestro Main storyboard. Allí nos vamos, al ViewController (el único que hay). Y lo que hacemos es abrir la librería para añadir una UIView a la View del ViewController.

Ahora añadimos una UIView, dentro del ViewController del Storyboard
Ahora añadimos una UIView, dentro del ViewController del Storyboard

Añadimos también las contrains: top, bottom, leading y trailing. Y una vez añadidas las constraints, vamos al Inpector de identidad, y allí decimos que esta view sea una CustomView.

Le asignamos la clase CustomView a la UIView que acabamos de añadir
Le asignamos la clase CustomView a la UIView que acabamos de añadir

Y ahora vamos a compilar a ver qué ocurre:

Aparece correctamente la vista CustomView en ViewController (Storyboard)
Aparece correctamente la vista CustomView en ViewController (Storyboard)

Aparece nuestra View CustomView bien integrada en el UIViewController de nuestro Storyboard. Hemos reaprovechado una vista en un XIB y también en un Storyboard.

Ahora lo que vamos hacer, es ver cómo navegar del XIB ViewController2 al XIB ViewController3. Pero, primero debemos crear nuestro ViewController3, vamos hacerlo, pulsamos COMMAND+N y creamos una Cocoa Touch Class con base class UIViewController, y llamamos a esta nueva clase ViewController3

Una vez creado, voy a añadir un UILabel con constraints (top y leading) que ponga Suscríbete a SwiftBeta, y una vez finalizado, vamos a nuestro ViewController2. Ahora vamos a añadir un IBAction para que cuando pulsemos el UIButton, se presente nuestro nuevo ViewController3.

Creamos un ViewController3 con su XIB
Creamos un ViewController3 con su XIB

Vamos a nuestro ViewController2. Vamos a pulsar la tecla OPTION para tener el XIB justo al lado y así podamos crear el IBAction fácilmente, aunque ahora que lo pienso, te voy a enseñar otra manera de hacer la conexión. Primero, vamos a crear el siguiente método en ViewController2:

    @IBAction func navigateToViewController3() {
        print("TODO")
    }
Método para navegar de un XIB a otro XIB

Ahora, pulsamos la tecla OPTION (o alt) y clickamos en el XIB del ViewController2. De esta manera podemos realizar la conexión entre esta clase y la acción del UIButton del XIB.

Conectamos ViewController2 con el UIButton de su XIB
Conectamos ViewController2 con el UIButton de su XIB

Esta vez, en lugar de ir del XIB (o Storyboard) a la clase para crear el IBAction, primero hemos creado el IBAction y luego hemos ido al XIB.

Ahora que ya tenemos hecha esta conexión, vamos a añadir el código necesario para navegar al ViewController3.

    @IBAction func navigateToViewController3() {
        let viewController3 = ViewController2(nibName: "ViewController3",
                                              bundle: nil)
        self.present(viewController3,
                     animated: true)
    }
Método para navegar al XIB ViewController3 desde XIB ViewController2

Si compilamos y probamos nuestra app, podemos navegar correctamente al ViewController3.

Conclusión

Hoy hemos aprendido a usar los XIBs en el Interface Builder. Usar XIBs tiene sus ventajas e inconvenientes comparado con los Storyboards o a crear las vistas directamente por código.
Hemos creado ViewControllers y UIView usando XIBs y también hemos aprendido a cómo navegar del Storyboard a un XIB, y de un XIB a otro XIB. Un video muy completo y entretenido.

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