Introducción a las animaciones en UIKit
Introducción a las animaciones en UIKit

Animar vistas en UIKit creadas por código y Storyboard (con y sin Auto Layout)

Aprende a crear animaciones en tu app iOS. Hay diferentes maneras de añadirlas a tus apps con UIKit. Vamos a explorar a cómo animar vistas creadas por código y también a vistas creadas en el Storyboard de Xcode.

SwiftBeta

Tabla de contenido


👇 SÍGUEME PARA APRENDER SWIFTUI, SWIFT, XCODE, etc 👇
Aprende a crear animaciones en UIKit
Aprende a crear animaciones en UIKit

Hoy en SwiftBeta vamos a aprender a animar las vistas de nuestro ViewController. Como developers, aparte de enfocarnos en la arquitectura, tests, buenas prácticas, etc también debemos dedicar tiempo a la UI, ya que es en lo primero que se fijan los users.

Vamos a aprender a crear animaciones:

  • En vistas creadas por código sin y con Autolayout
  • Y también vamos a ver el ejemplo de vistas creadas con el Storyboard con y sin Auto Layout

Es decir veremos ejemplos usando constraints y sin constraints. Modificaremos unas propiedades para animar las vistas de nuestra app. Después de ver este video serás capaz de crear tus propias animaciones. Va a ser un video muy completo en el que te voy a enseñar muchas cosas interesantes.

Creamos el proyecto en Xcode

Como siempre vamos a crear el proyecto en Xcode. Es muy importante marcar la opción de Storyboard ya que estamos con la serie de UIKit.

Una vez creado nuestro proyecto, vamos a nuestro ViewController. Allí vamos a crear una UIView y la vamos añadir a la vista de nuestro ViewController.

class ViewController: UIViewController {
    let myView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = true
        view.backgroundColor = .systemGreen
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        myView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        myView.center = view.center
    }
}
Creamos una vista y la añadimos a la jerarquía de vistas

Al compilar vemos una vista cuadrada centrada en la view del View Controller. A continuación vamos a animar la vista que acabamos de añadir, vamos a crear nuestra primera animación.

UIView.animate en UIKit

Hay varias maneras de animar una vista usando UIKit, ahora vamos a ver una muy sencilla. Tan solo debemos usar el método estático animate

Métodos de UIView.animate para poder animar nuestra vista
Métodos de UIView.animate para poder animar nuestra vista

Al añadir UIView.animate vemosa una serie de métodos, en este caso vamos a usar el tercer.

UIView.animate(withDuration: 2) {
	<#code#>
}
Método que nos va a permitir animar una vista en UIKit
  • En el primer parámetro añadimos el tiempo que va a durar nuestra animación, este tiempo son segundos (En nuestro caso la animación durará 2 segundos).
  • En el segundo parámetro añadimos el bloque código con los cambios que queremos animar, aquí modificamos propiedades de la vista

Vamos a ver un ejemplo real:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        myView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
        myView.center = view.center
        
        UIView.animate(withDuration: 2) {
            self.myView.frame = CGRect(x: 0, y: 200, width: 100, height: 100)
        }
    }
Creamos nuestra primera animación en UIKit

Si compilamos nuestro código, vemos como nuestra vista se hace más pequeña y se posiciona en la coordenada X = 0 e Y = 200. Acabamos de crear nuestra primera animación!

Puedes jugar con algunas propiedades y dar valores para crear tus propias animaciones:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        myView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        myView.alpha = 0.0
        myView.center = view.center
        
        UIView.animate(withDuration: 2) {
            self.myView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.myView.center = self.view.center
            self.myView.alpha = 1.0
            self.myView.layer.cornerRadius = 50
        }
    }
Creamos una animación más compleja en UIKit

Pero qué ocurre si queremos personalizar un poco más nuestras animaciones? es decir, añadir un delay antes de que empiecen, velocidad, tipos de animación curva disponibles en UIKit, etc

UIView.animate(withDuration,delay,usingSpringDamping,etc)

Acabamos de crear nuestra primera animación usando un método muy sencillo, ahora vamos a utilizar el mismo pero que acepta más parámetros:

Método de UIView que espera más parámetros y nos permite crear animaciones más personalizadas
Método de UIView que espera más parámetros y nos permite crear animaciones más personalizadas
Añade todos los parámetros, ya que vamos explorar cada uno de ellos aunque sean opcionales

Vamos a ve uno por uno:

  • duration: la duración total de la animación. Este valor son segundos.
  • delay: tiempo que debe pasar hasta que nuestra animación empiece. Este tiempo también es en segundos.
  • dampingRation: esta es la relación de amortiguamiento para la animación, un valor cercano al 0 hará que oscile más rápido (esto lo veremos más claro en el siguiente ejemplo)
  • velocity: La velocidad inicial de la animación
  • options: Una máscara de opciones para aplicare a nuestra animaciones, estas máscaras son de tipo UIViewAnimationOptions, y podemos especificar si queremos que nuestra animación sea más rápida al inicio, final, inicio/final, etc
  • animations: Bloque de código con las animaciones que queremos realizar en nuestra vista
  • completion: Bloque de código que se ejecuta al finalizar la animación

Vamos a ver un ejemplo (comenta la propiedad donde modificamos el alpha, en este ejemplo no la vamos a modificar)

        UIView.animate(withDuration: 2,
                       delay: 2,
                       usingSpringWithDamping: 0.5,
                       initialSpringVelocity: 0.25,
                       options: .curveEaseInOut) {
            self.myView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.myView.center = self.view.center
            //self.myView.alpha = 1.0
            self.myView.layer.cornerRadius = 50
        } completion: { isFinished in
            print("Did finish? \(isFinished)")
        }
Usamos otro método para crear animaciones que recibe varios parámetros que podemos customizar

Al compilar qué ocurre? vemos un efecto diferente a los anteriores ejemplos. Hay un efecto como de rebote. Este efecto lo hemos creado nosotros pasándole unos valores al método UIView.animate. Ahora, vamos a modificar algunos valores para que la oscilación sea más clara:

        UIView.animate(withDuration: 5,
                       delay: 2,
                       usingSpringWithDamping: 0.1,
                       initialSpringVelocity: 1,
                       options: .curveEaseIn) {
            self.myView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
            self.myView.center = self.view.center
            //self.myView.alpha = 1.0
            self.myView.layer.cornerRadius = 50
        } completion: { isFinished in
            print("Did finish? \(isFinished)")
        }
Cambiamos el efecto final de nuestra animación modificando el damping, velocity y tamaño

Acabamos de aprender a crear animaciones simples por código, pero cómo sería lo mismo si utilizaramos constraints? Vamos a ver a cómo aplicar animaciones a  constraints por código y usando el Storyboard. Empecemos primero por animar constraints por código

Animar constraints por Código

Ahora imagina que tenemos nuestra UIView centrada en el medio de nuestra vista, (la que hemos llamado myView) y la queremos mover a la parte superior de la vista. Para hacerlo vamos a crear el código necesario (usando Auto Layout).

class ViewController: UIViewController {
    let myView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .systemGreen
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        NSLayoutConstraint.activate([
            myView.heightAnchor.constraint(equalToConstant: 200),
            myView.widthAnchor.constraint(equalToConstant: 200),
            myView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            myView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}
Posicionamos nuestra vista usando contraints (auto layout)

Si compilamos, vemos que aparece un cuadrado en la parte central de nuestra vista del view controller. Perfecto, ahora necesitamos una referencia a una constraint para poder cambiarle el valor, vamos a crear la siguiente propiedad:

    var centerYConstraint: NSLayoutConstraint?
Creamos una referencia de la constraint que queremos animar

y vamos a modificar un poco el código:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        
        centerYConstraint = myView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        
        NSLayoutConstraint.activate([
            myView.heightAnchor.constraint(equalToConstant: 200),
            myView.widthAnchor.constraint(equalToConstant: 200),
            centerYConstraint!,
            myView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])
    }
Asignamos un valor a la propiedad de tipo constraint que hemos creado hace un momento

Si compilamos, vemos que tenemos exactamente lo mismo. La única diferencia es que ahora tenemos una referencia de nuestra constraint y la podemos modificar donde queramos.

A continuación vamos a añadir la animación que hará que nuestra vista se posicione en la parte superior de la vista de nuestro view controller, vas a ver lo sencillo que es:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        
        centerYConstraint = myView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        
        NSLayoutConstraint.activate([
            myView.heightAnchor.constraint(equalToConstant: 200),
            myView.widthAnchor.constraint(equalToConstant: 200),
            myView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            self.centerYConstraint!
        ])
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.animateConstraint()
        }
    }
    
    func animateConstraint() {
        UIView.animate(withDuration: 2, delay: 2) {
            self.centerYConstraint?.constant = -200
        }
    }
Animamos la constraint accediendo a la propiedad constant

Vamos a compilar, fíjate que no es el efecto que queríamos. Ha habido un salto y no se ha producido ninguna animación. Esto es por que necesitamos llamar a un método de UIKit dentro del bloque de nuestra animación.

El método es layoutIfNeeded, con este método forzamos a nuestra vista a que se actualice inmediatamente, de esta manera se realiza el update de la view necesario si hay algún cambio en las constraints.

Así que ahora, vamos a modificar el bloque de nuestra animación y añadimos la siguiente linea de código:

    func animateConstraint() {
        UIView.animate(withDuration: 2, delay: 2) {
            self.centerYConstraint?.constant = -200
            self.view.layoutIfNeeded()
        }
    }
Para animar constraints, necesitamos usar el método layoutIfNeeded

Si ahora compilamos, vemos el efecto que queríamos desde el principio. Acabamos de aprender a animar una constraint de Auto Layout por código. Vamos a ver exactamente lo mismo usando Storyboards.

Animar constraints en Storyboard

Vamos a crear nuestra UIView en el Storyboard. Vamos a crear la misma UIView de 200x200 y con el backgroundColor de systemGreen. A continuación vamos a crear las constraints (vamos a crear las mismas que hemos creado por código). Y una vez creadas vamos a abrir el editor justo al lado de nuestro Storyboard.

Vamos a crear una referencia de centerYConstraint. De esta manera podremos accede y modificar su valor por código.

@IBOutlet weak var centerYConstraint: NSLayoutConstraint!
Creamos un IBOutlet de una constraint que hemos creado desde nuestro Storyboard

Y ahora tenemos mucho código que no necesitamos en nuestro Storyboard. Voy a comentarlo rápidamente:

class ViewController: UIViewController {
    /*let myView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .systemGreen
        return view
    }()*/
    
    //var centerYConstraint: NSLayoutConstraint?
    @IBOutlet weak var centerYConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //view.addSubview(myView)
        
        /*centerYConstraint = myView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        
        NSLayoutConstraint.activate([
            myView.heightAnchor.constraint(equalToConstant: 200),
            myView.widthAnchor.constraint(equalToConstant: 200),
            myView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            self.centerYConstraint!
        ])*/
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.animateCoinstrant()
        }
    }
    
    func animateCoinstrant() {
        UIView.animate(withDuration: 2, delay: 2) {
            self.centerYConstraint?.constant = -200
            self.view.layoutIfNeeded()
        }
    }
}
Utilizamos el mismo código que teníamos la animar la constraint por código

Si compilamos, obtenemos exactamente el mismo resultado que teníamos por código.

En este caso hemos modificado la constraint de una de las vistas de nuestra app. Pero quizás tienes alguna vista en tu app en la que no usas Auto Layout, entonces podrías implementar el mismo código del primer ejemplo, es decir:

  • Elimina las constraints del Storyboard
  • Crea una referencia @IBOutlet de la view del Storyboard

Una vez hecho los pasos de arriba, puedes copiar y pegar el ejemplo que hemos usado al principio del video:

class ViewController: UIViewController {
    /*let myView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .systemGreen
        return view
    }()*/
    
    //var centerYConstraint: NSLayoutConstraint?
    
    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(myView)
        
        myView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        myView.alpha = 0.0
        myView.center = view.center
        
        UIView.animate(withDuration: 2) {
            self.myView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
            self.myView.center = self.view.center
            self.myView.alpha = 1.0
            self.myView.layer.cornerRadius = 50
        }
    }
}
Animamos una vista que hemos creado directamente en el Storyboard

Conclusión

Hoy hemos aprendido a cómo crear simples animaciones dentro de nuestras apps. Hemos visto el método animate del framework UIKit para poder animar vistas de nuestro view controller. Hemos entrado en detalle en cómo animar:

  • Views por código sin Auto Layout
  • Views por código con Auto Layout (usando constraints)
  • Views creadas en Storyboard con Auto Layout (usando constraints)
  • Views creadas en Storyboard sin Auto Layout