Mejores animaciones de iOS con CATransaction

Core Animation, el marco de Cocoa responsable de la mayoría de las animaciones de iOS y macOS, es un sistema complejo con muchas funcionalidades ocultas y menos conocidas.

Core Animation maneja tus animaciones detrás de escena, y al conocer un poco más cómo funciona podemos aprovecharlo al máximo y crear animaciones ajustadas.

Las animaciones son fáciles. Excepto cuando no lo son.
BetterAnimations.playground

Las animaciones son la mejor manera de mostrar los cambios a un usuario. El UIKit de Apple (o AppKit para macOS) hace que saltar a las animaciones sea muy fácil. Probablemente haya usado UIKit para la mayoría de sus encuentros de animación, y el código probablemente se ve así:

Es limpio y fácil de usar. Los marcos UIKit / AppKit de nivel superior (que se encuentran por encima de Core Animation) hacen un gran trabajo al facilitar las animaciones. Sin embargo, hay algunas dificultades cuando quieres movimientos más complejos.

Animación de ejemplo

Considere esto: tiene un UIButton, un descendiente de UIView, y desea que sea una vista circular, y cuando se toca cambiará el tamaño de la vista.

Suena sencillo. Podemos animar styledButton.layer.cornerRadius y configurarlo a la mitad del ancho a medida que cambia nuestro marco. Pero espera ... hay un problema. UIView.animate (...) solo manejará animaciones de propiedades de vista, no animaciones de propiedades de capa. Si intentamos cambiar el marco de styledButton y el cornerRadius de styledButton en el bloque de animación a continuación, obtenemos un efecto no deseado:

Resultado del segmento de código

El cuadro se anima correctamente, sin embargo, el cornerRadius salta directamente a su nuevo valor sin animar. Más adelante hablaremos sobre CATransaction y cómo resolverá este problema. Pero primero, es bueno saber qué sucede bajo el capó de nuestras animaciones y por qué ocurre esto.

Animación interna del núcleo

Las instancias UIView (así como las instancias NSView respaldadas por capas) tienen una propiedad CALayer llamada capa en la que operan las animaciones. La vista delega la representación de sus capas a Core Animation. Sin embargo, cuando se agregan animaciones a la capa, las propiedades de la capa no se modifican directamente.

Core Animation posee dos jerarquías de árbol paralelas: un árbol de capas modelo y un árbol de capas de presentación. Estos se pueden ver en las propiedades de presentación de capas y modelos de capas de CALayer. Es el PresentationLayer el responsable de mostrar cualquier cambio durante el curso de una animación. Si tuviera que animar la propiedad borderWidth de una capa y observar el valor durante la animación, el valor borderWidth solo cambiará en el árbol de capas de presentación durante la animación.

A través de CABasicAnimation podemos animar las propiedades de la capa. Pero no deje que la palabra "Básico" lo desanime: esta es una de las herramientas de animación más poderosas para ajustar sus animaciones.

Una nota práctica: es una buena práctica de animación establecer el valor que está animando en el nuevo valor antes de agregar la animación. Es común ver la propiedad fillMode establecida en kCAFillModeForwards y isRemovedOnCompletion establecida en false. Sin embargo, lo que esto hace es esencialmente "pausar" nuestra capa de presentación al final de la animación. Es una buena práctica mantener sincronizadas las capas de modelo y presentación, y al establecer el valor antes de agregar la animación, podemos hacer exactamente esto.

CATransaction - Para suavizar tus animaciones

Okay. De vuelta a nuestro ejemplo de UIButton de antes. Queremos animar la propiedad cornerRadius de la capa y animar la propiedad de marco de la vista al mismo tiempo y asegurarnos de que se mantengan perfectamente sincronizados para la mejor animación.

CATransacción al rescate!

CATransaction es una clase a menudo pasada por alto por la mayoría de los desarrolladores. El trabajo de CATransaction es agrupar varias acciones relacionadas con la animación. Asegura que los cambios de animación deseados se comprometan con Core Animation al mismo tiempo.

Aquí comenzamos una transacción y podemos cambiar cualquier propiedad habilitada para Core Animation, que se animará una junto a la otra una vez que se confirme.

Poniendolo todo junto

Por eso queremos animar la capa y ver las propiedades al mismo tiempo. Este es un uso perfecto para CATransaction. ¡Incluso podemos utilizar nuestro código UIView.animate () y CABasicAnimation existentes!

Animación resultante

En este ejemplo, uso una animación UIView y una animación CABasic para completar esta tarea. Todo lo coordinado por CATransaction se pasará a otras animaciones. Por ejemplo, la función setAnimationDuration (dur: CFTimeInterval) se aplicará a CABasicAnimation, por lo que no necesitamos especificar ninguna duración. Sin embargo, dado que UIView.animate () nos hace especificar la duración, simplemente podemos establecer la duración a la misma especificada en el setAnimationDuration de CATransaction.

Animaciones de fotogramas clave personalizados

Otro buen uso es utilizar una función de sincronización de CATransaction para definir su propia curva de animación bezier. Si envuelve su UIView.animate () dentro de una CATransaction, puede obtener un control preciso sobre su curva de animación:

Animación final con función de sincronización

Resumen

CATransaction es un poderoso coordinador para sus animaciones y le ahorrará toneladas de tiempo mientras le brinda un control preciso sobre sus animaciones. Además, no hay un montón de bloques anidados, lo que siempre es una ventaja de legibilidad.

El proyecto completo de juegos Swift 3 con CATransaction junto con UIKit y CABasicAnimation se puede encontrar aquí:

¡Gracias por leer! Si tiene preguntas o sugerencias, ¡no dude en comunicarse!