Articles

Realización De Animaciones iOS En Vistas Con UIKit Y UIView

  • 14 min leer
  • Animación,iOS,interfaz de usuario,Móvil
  • Guardado para leer sin conexión
  • Compartir en Twitter, LinkedIn
Este artículo pretende ser una introducción a iOS animaciones exhaustivo cubriendo diferentes formas de hacerlo. Comenzamos entendiendo los conceptos básicos de las animaciones, pasamos a los marcos Centrales construyendo un solo ejemplo utilizando los diferentes métodos ofrecidos y, finalmente, buscamos formas de ajustar el rendimiento.

He sido desarrollador de iOS durante más de una década y rara vez he visto artículos que consolidan todas las formas posibles de realizar animaciones en iOS. Este artículo pretende ser una introducción a las animaciones de iOS con la intención de cubrir exhaustivamente las diferentes formas de hacer lo mismo.

Dada la extensión del tema, cubriríamos cada parte sucintamente a un nivel bastante alto. El objetivo es educar al lector con un conjunto de opciones para agregar animaciones a su aplicación iOS.

Antes de comenzar con temas relacionados con iOS, echemos un vistazo a la velocidad de animación.

Animación a 60 FPS

Generalmente en los vídeos, cada fotograma está representado por una imagen y la velocidad de fotogramas determina el número de imágenes invertidas en la secuencia. Esto se denomina «fotogramas por segundo» o FPS.

FPS determina el número de imágenes fijas volteadas en un segundo, lo que significa literalmente que cuanto más cantidad de imágenes/ fotogramas, más detalles/ información se muestran en el video. Esto también es válido para las animaciones.

El FPS se utiliza normalmente para determinar la calidad de las animaciones. Hay una opinión popular de que cualquier buena animación debe ejecutarse a 60 fps o más, cualquier cosa menor a 60 fps se sentiría un poco apagada.

¿Quieres ver la diferencia entre 30 FPS y 60 FPS? ¡Mira esto!

¿Notaste la diferencia? Los ojos humanos definitivamente pueden sentir el nerviosismo en fps más bajos. Por lo tanto, siempre es una buena práctica asegurarse de que cualquier animación que cree se adhiera a la regla básica de correr a 60 FPS o más. Esto lo hace sentir más realista y vivo.

Después de ver los FPS, ahora profundicemos en los diferentes marcos de iOS principales que nos proporcionan una forma de realizar animaciones.

Marcos básicos

En esta sección, tocaremos los marcos en el SDK de iOS que se pueden usar para crear animaciones de vistas. Haremos un paseo rápido por cada uno de ellos, explicando su conjunto de características con un ejemplo relevante.

Animaciones UIKit / UIView

UIView es la clase base para cualquier vista que muestre contenido en aplicaciones iOS.

UIKit, el framework que nos da UIView, ya nos proporciona algunas funciones básicas de animación que hacen que sea conveniente para los desarrolladores lograr más haciendo menos.

La API, UIView.animate, es la forma más fácil de animar vistas, ya que las propiedades de cualquier vista se pueden animar fácilmente proporcionando los valores de propiedad en la sintaxis basada en bloques.

En UIKit animaciones, se recomienda modificar la animación de propiedades de UIVIew habrá repercusiones donde las animaciones podrían causar la vista para terminar en un estado inesperado.

animation(withDuration: animations: completion)

Este método toma la duración de la animación, un conjunto de cambios de propiedades animables de la vista que deben animarse. El bloque de finalización devuelve una llamada cuando la vista termina de realizar la animación.

Casi cualquier tipo de animación como movimiento, escala, rotación,desvanecimiento, etc. en una vista se puede lograr con esta única API.

Ahora, considere que desea animar un cambio de tamaño de botón o que desea que una vista en particular se acerque a la pantalla. Así es como podemos hacerlo usando la API UIView.animate :

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3}

Esto es lo que estamos haciendo aquí:

  1. Llamamos al método UIView.animate con un valor de duración que se le pasa que representa cuánto tiempo debe ejecutarse la animación, descrita dentro del bloque.
  2. Configuramos el nuevo marco del botón que debe representar el estado final de la animación.
  3. Configuramos el botón center con el centro de su superview para que permanezca en el centro de la pantalla.

El bloque de arriba de la animación con el código debe activar la animación de botón en el marco del cambio de la imagen actual:

Width = 0, Height = 0

al final de la trama:

Width = Height = newButtonWidth

Y esto es lo que la animación se vería:

animateWithDuration

Este método es como una extensión del método animate donde puede hacer todo lo que pueda realizar en la API anterior con algunos comportamientos físicos añadidos a las animaciones de la vista.

Por ejemplo, si desea lograr efectos de amortiguación de muelles en la animación que hemos realizado anteriormente, así es como se vería el código:

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}), completion: nil)

Aquí está el conjunto de parámetros que usamos:

  1. duration
    Representa la duración de la animación determinar cuánto tiempo el bloque de código debe ejecutarse.
  2. delay
    Representa el retraso inicial que queremos tener antes del inicio de la animación.
  3. SpringWithDamping
    Representa el valor del efecto elástico que queremos que se comporte en la vista. El valor debe estar entre 0 y 1. Cuanto menor sea el valor, mayor será la oscilación del resorte.
  4. velocity
    Representa la velocidad a la que la animación de inicio.
  5. options
    Tipo de curva de animación que desea aplicar a la vista de la animación.
  6. Finalmente, el bloque de código donde fijamos el marco del botón que necesita ser animado. Es el mismo que la animación anterior.

Y así es como se vería la animación con la configuración de animación anterior:

UIViewPropertyAnimator

Para un poco más de control sobre las animaciones, UIViewPropertyAnimator es útil donde nos proporciona una forma de pausar y reanudar las animaciones. Puede tener una sincronización personalizada y hacer que su animación sea interactiva e interrumpible. Esto es muy útil cuando se realizan animaciones que también son interactuables con las acciones del usuario.

El gesto clásico de «Deslizar para desbloquear» y la animación de descarte/ expansión de la vista del reproductor (en la aplicación Música) son ejemplos de animaciones interactivas e interrumpibles. Puede comenzar a mover una vista con el dedo, luego soltarla y la vista volverá a su posición original. Alternativamente, puede capturar la vista durante la animación y continuar arrastrándola con el dedo.

el Siguiente es un ejemplo sencillo de cómo podríamos conseguir que la animación utilizando UIViewPropertyAnimator:

let newButtonWidth: CGFloat = 60let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}animator.startAnimation() //2

he Aquí lo que estamos haciendo:

  1. Llamamos a la API UIViewProperty pasando la duración y la curva de animación.
  2. A diferencia de las dos vistas anteriores.API de animate, la animación no se iniciará a menos que la especifique usted mismo, es decir, que tenga el control total del proceso/ flujo de animación completo.

Ahora, digamos que quieres tener aún más control sobre las animaciones. Por ejemplo, desea diseñar y controlar todos y cada uno de los fotogramas de la animación. Hay otra API para eso, animateKeyframes. Pero antes de ahondar en ello, veamos rápidamente lo que es un fotograma, en una animación.

¿Qué Es Un frame?

Una colección de cambios/ transiciones de fotogramas de la vista, desde el estado inicial hasta el estado final, se define como animation y cada posición de la vista durante la animación se llama como frame.

animateKeyframes

Esta API proporciona una forma de diseñar la animación de tal manera que pueda definir varias animaciones con diferentes tiempos y transiciones. Publica esto, la API simplemente integra todas las animaciones en una experiencia perfecta.

supongamos que queremos mover nuestro botón en la pantalla de forma aleatoria. Veamos cómo podemos usar la API de animación de fotogramas clave para hacerlo.

UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start }})

Aquí está el desglose:

  1. duration
    Llamar a la API pasando en la duración de la animación.
  2. Duración del retardo inicial de la animación.
  3. options
    El tipo de curva de animación que desea aplicar a la vista de la animación.
  4. animations
    Bloque que toma todas las animaciones de fotogramas clave diseñadas por el desarrollador/ usuario.
  5. addKeyFrame
    Llame a la API para diseñar todas y cada una de las animaciones. En nuestro caso, hemos definido cada movimiento del botón. Podemos tener tantas animaciones como necesitemos, agregadas al bloque.
  6. relativeStartTime
    Define la hora de inicio de la animación en la colección del bloque de animación.
  7. relativeDuration
    Define la duración total de esta animación.
  8. center
    En nuestro caso, simplemente cambiamos la propiedad central del botón para moverlo por la pantalla.

Y así es como se ven las animaciones finales:

CoreAnimation

Cualquier animación basada en UIKit se traduce internamente a animaciones básicas. Por lo tanto, el framework Core Animation actúa como una capa de respaldo o columna vertebral para cualquier animación UIKit. Por lo tanto, todas las API de animación de UIKit no son más que capas encapsuladas de las API de animación principales de una manera fácil de consumir o conveniente.

Las API de animación de UIKit no proporcionan mucho control sobre las animaciones que se han realizado en una vista, ya que se utilizan principalmente para las propiedades animables de la vista. Por lo tanto, en tales casos, en los que pretenda tener control sobre cada fotograma de la animación, es mejor usar las API de animación básicas subyacentes directamente. Alternativamente, tanto las animaciones UIView como las animaciones core también se pueden usar en conjunto.

UIView + Core Animation

Veamos cómo podemos recrear la misma animación de cambio de botón junto con especificar la curva de tiempo utilizando las API de animación UIView y Core.

Podemos utilizar las funciones de temporización de CATransaction, que le permiten especificar y controlar la curva de animación.

Veamos un ejemplo de una animación de cambio de tamaño de botón con su radio de esquina utilizando la función de temporización de CATransactiony una combinación de animaciones de vista UIView:

let oldValue = button.frame.width/2let newButtonWidth: CGFloat = 60/* Do Animations */CATransaction.begin() //1CATransaction.setAnimationDuration(2.0) //2CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3// View animations //4UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}// Layer animationslet cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5cornerAnimation.fromValue = oldValue //6cornerAnimation.toValue = newButtonWidth/2 //7button.layer.cornerRadius = newButtonWidth/2 //8button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9CATransaction.commit() //10

Aquí está el desglose:

  1. begin
    Representa el inicio del bloque de código de animación.
  2. duration
    Duración total de la animación.
  3. curve
    Representa la curva de tiempo que debe aplicarse a la animación.
  4. UIView.animate
    Nuestra primera animación para cambiar el marco de un botón.
  5. CABasicAnimation
    Creamos el objeto CABasicAnimationhaciendo referencia al cornerRadius del botón como la ruta de acceso, ya que eso es lo que queremos animar. De manera similar, si desea tener control de nivel granular sobre las animaciones de fotogramas clave, puede usar la clase CAKeyframeAnimation.
  6. fromValue
    Representa el valor inicial de la animación, es decir, el cornerRadius valor del botón desde donde la animación debe empezar.
  7. toValue
    Representa el valor final de la animación, es decir, el final cornerRadius valor del botón donde la animación debe terminar.
  8. cornerRadius
    debemos establecer el cornerRadius propiedad del botón con el valor final de la animación más el botón del cornerRadius valor se auto-volvió a su valor inicial después de que finalice la animación.
  9. addAnimation
    Adjuntamos el objeto de animación que contiene la configuración de todo el proceso de animación a la capa representando la ruta de teclado para la que se debe realizar la animación.
  10. commit
    Representa el final del bloque de código de animación y comienza la animación.

Así es como se vería la animación final:

Este blog es una gran lectura para ayudar a crear animaciones más avanzadas, ya que lo guía cuidadosamente a través de la mayoría de las API principales del marco de animación con instrucciones a través de cada paso del camino.

UIKitDynamics

UIKit Dynamics es el motor de física para UIKit que le permite agregar cualquier comportamiento físico como colisión, gravedad, empuje, ajuste, etc. a los controles de UIKit.

UIKitDynamicAnimator

Esta es la clase admin del framework UIKit Dynamics que regula todas las animaciones activadas por cualquier control de interfaz de usuario dado.

UIKitDynamicBehavior

Le permite agregar cualquier comportamiento físico a un animador que luego le permite realizar en la vista adjunta.

Los diferentes tipos de comportamientos para la dinámica de Uikits incluyen:

  • UIAttachmentBehavior
  • UICollisionBehavior
  • UIFieldBehavior
  • UIGravityBehavior
  • UIPushBehavior
  • UISnapBehavior

La arquitectura de UIKitDynamics se ve algo como esto. Tenga en cuenta que los elementos del 1 al 5 se pueden reemplazar con una sola vista.

Apliquemos un poco de comportamiento físico a nuestro botón. Veremos cómo aplicar gravedad al botón para que nos dé la sensación de tratar con un objeto real.

var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3

Aquí está el desglose:

  1. UIKitDynamicAnimator
    Hemos creado un objeto UIKitDynamicAnimator que actúa como un orquestador para realizar animaciones. También hemos pasado la vista superior de nuestro botón como vista de referencia.
  2. UIGravityBehavior
    Hemos creado un objeto UIGravityBehavior y pasamos nuestro botón a los elementos de matriz en los que se inyecta este comportamiento.
  3. addBehavior
    Hemos añadido el objeto gravity al animador.
    Esto debería crear una animación como se muestra a continuación:

    Observe cómo el botón se desprende del centro (su posición original) de la pantalla hacia la parte inferior y más allá.

    Deberíamos decirle al animador que considere que la parte inferior de la pantalla es el suelo. Aquí es donde UICollisionBehavior entra en escena.

    var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6
  4. UICollisionBehavior
    Hemos creado un UICollisionBehavior objeto y pasa por el botón de modo que el comportamiento se añade el elemento.
  5. translatesReferenceBoundsIntoBoundary
    Habilitar esta propiedad le indica al animador que tome el límite de las vistas de referencia como el final, que es la parte inferior de la pantalla en nuestro caso.
  6. addBehavior
    Hemos añadido el comportamiento de colisión al animador aquí.
    Ahora, nuestro botón debe golpear el suelo, de pie todavía, como se muestra a continuación:

    Eso es maravilloso, ¿no?Ahora, intentemos agregar un efecto de rebote para que nuestro objeto se sienta más real. Para ello, usaremos la clase UIDynamicItemBehavior.

    var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!var bouncingBehavior : UIDynamicItemBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6//Adding the bounce effectbouncingBehavior = UIDynamicItemBehavior(items: ) //7bouncingBehavior.elasticity = 0.75 //8dynamicAnimator.addBehavior(bouncingBehavior) //9
  7. UIDynamicItemBehavior
    Hemos creado un UIDynamicItemBehavior objeto y pasar a lo largo de el botón de modo que el comportamiento se añade el elemento.
  8. elasticity
    El valor debe estar entre 0-1, representa la elasticidad, es decir, el número de veces que el objeto debe rebotar sobre y desde el suelo cuando se golpea. Aquí es donde ocurre la magia: al ajustar esta propiedad, puede diferenciar entre diferentes tipos de objetos como bolas, botellas, objetos duros, etc.
  9. addBehavior
    Hemos añadido el comportamiento de colisión al animador aquí.

Ahora, nuestro botón debería rebotar cuando toque el suelo como se muestra a continuación:

Este repositorio es bastante útil y muestra todos los comportamientos de UIKitDynamics en acción. También proporciona código fuente para jugar con cada comportamiento. ¡Eso, en mi opinión, debería servir como una extensa lista de formas de realizar animaciones de iOS en vistas!

En la siguiente sección, echaremos un vistazo a las herramientas que nos ayudarán a medir el rendimiento de las animaciones. También le recomendaría que busque formas de optimizar su compilación de Xcode, ya que ahorrará una gran cantidad de tiempo de desarrollo.

Ajuste de rendimiento

En esta sección, veremos formas de medir y ajustar el rendimiento de las animaciones de iOS. Como desarrollador de iOS, es posible que ya haya utilizado instrumentos Xcode como Fugas de memoria y Asignaciones para medir el rendimiento de la aplicación en general. Del mismo modo, hay instrumentos que se pueden utilizar para medir el rendimiento de las animaciones.

Core Animation Instrumento

Pruebe el instrumento Core Animation y podrá ver los FPS que ofrece la pantalla de su aplicación. Esta es una excelente manera de medir el rendimiento/ velocidad de cualquier animación renderizada en su aplicación iOS.

Dibujo

El FPS se reduce enormemente en la aplicación que muestra contenido pesado como imágenes con efectos como sombras. En tales casos, en lugar de asignar la imagen directamente a la propiedad image de UIImageView, intente dibujar la imagen por separado en un contexto utilizando las API de gráficos Principales. Esto reduce excesivamente el tiempo de visualización de la imagen al realizar la lógica de descompresión de la imagen de forma asíncrona cuando se realiza en un subproceso separado en lugar del subproceso principal.

Rasterización

La rasterización es un proceso utilizado para almacenar en caché información de capas complejas para que estas vistas no se vuelvan a dibujar cada vez que se rendericen. El redibujado de vistas es la causa principal de la reducción de FPS y, por lo tanto, es mejor aplicar rasterización en vistas que se van a reutilizar varias veces.

Terminando

Para concluir, también he resumido una lista de recursos útiles para animaciones de iOS. Puede encontrar esto muy útil cuando se trabaja en animaciones de iOS. Además, también puede encontrar este conjunto de herramientas de diseño útiles como un paso (de diseño) antes de profundizar en las animaciones.