Animando gradientes en React Native

Estoy trabajando en un proyecto personal llamado KaoCards, una aplicación de tarjetas para recordar los nombres y las caras de las personas. Cuando diseñé el producto pensé que sería genial tener un degradado animado como fondo, pero cuando intenté implementarlo, resultó ser más trabajo de lo que pensaba.

Así que aquí está la historia de cómo logré que funcione. Si quieres el TL; DR, hice un repositorio que puedes seguir.

Un intento ingenuo.

Si quieres entender esto, es importante saber por qué mi primer intento no funcionó.

Para mostrar un gradiente en React Native, las personas usan un proyecto llamado react-native-linear-gradient. Quería ver si alguien había intentado animar los colores, y encontré el ejemplo de transición de gradiente animado en ese repositorio. Mirando a través del código, tuve esta reacción:

No entendía por qué necesitaba dos clases, por qué había tanto código. No pensé que necesitarías tanto. Decidí que no iba a molestarme en entender todo eso. Pensé que la forma de hacer esto debería ser bastante simple:

  1. Cree un componente AnimatedLinearGradient usando Animate.createAnimatedComponent
  2. Interpola algunos colores y pásalos a AnimatedLinearGradient

Simple, verdad? Aquí está la fuente (se bloqueará). Hice una aplicación experimental, la ejecuté y luego, womp womp. Obtenemos el error:

El valor JSON `` de tipo NSNull no se puede convertir a UIColor. ¿Olvidó llamar a processColor () en el lado de JS?

Algo en el futuro no estaba obteniendo valores de colores. Entonces recurrí a Twitter para obtener ayuda:

Jason Brown respondió con la idea clave:

Aaahhh ok! Animated no funciona con matrices. Aunque pensé que estaba haciendo todo correctamente, la biblioteca animada no procesa los valores de los accesorios de la matriz, por lo que el componente nativo subyacente está obteniendo basura en lugar de obtener colores animados.

Quedó claro por qué el ejemplo original era tan grande.

Construyéndolo correctamente.

Ok, entendiendo esta limitación sobre Animated, modifiquemos nuestro plan de juego y hagámoslo un poco más robusto.

  1. Queremos que nuestro componente principal, AnimatedGradient, funcione igual que LinearGradient. Debería tomar una variedad de colores.
  2. Queremos que ocurra una transición cuando cambiemos los accesorios de colores. Para hacer esto, AnimatedGradient necesita hacer un seguimiento de los colores anteriores.
  3. Como no podemos animar valores en matrices, podemos construir un componente GradientHelper que tome colores individualmente y llamar a Animated.createAnimatedComponent sobre eso. GradientHelper colocará los valores en una matriz y los pasará al componente LinearGradient desde el paquete react-native-linear-gradient.

Para simplificar las cosas para este ejemplo, vamos a suponer que la matriz de colores solo tiene 2 valores.

Componente gradiente animado

Código fuente

Primero, crearemos un AnimatedGradientHelper a partir de nuestro GradientHelper, que haremos en un momento.

En el constructor de AnimatedGradient, inicializaremos un campo de estado prevColors para realizar un seguimiento de los colores anteriores. También inicializamos un Animated.Value llamado tweener.

En getDerivedStateFromProps, tomamos el valor state.colors y nos quedamos en state.prevColors. Configuramos el nuevo state.colors y restablecemos el tweener.

En componentWillUpdate (también conocido como cuando cambian los accesorios), haremos que el tweener se mueva de 0 a 1.

En el método de renderizado, utilizamos el tweener, prevColors y los colores para crear dos interpolaciones de color y las pasamos individualmente a nuestro AnimatedGradientHelper.

Gradient Helper

Código fuente

En GradientHelper, todo lo que estamos haciendo es tomar los accesorios color1 y color2, ponerlos en una matriz y pasarlos a LinearGradient. Estamos haciendo esto porque necesitamos sortear las limitaciones de Animated.

Y eso es lo esencial. Aquí está la demostración:

Ahora sabemos por qué el ejemplo original es tan grande. Tenía que hacer todo esto y manejar gradientes con más de 2 colores.

Pero espera, ¿qué más podemos animar?

De hecho, podemos dar un paso más y animar otras propiedades. El componente LinearGradient le permite especificar coordenadas para el inicio y el final del gradiente. ¿Por qué no interpolarlos también? Aquí hay un método de renderizado actualizado. Probablemente puedas adivinar lo que sucedió en el resto del componente. Fuente

Solo necesitaremos modificar un poco nuestro GradientHelper haciendo algo con los accesorios. Fuente

Y ahora tenemos una demostración más genial.

Pude combinar este degradado animado con otras animaciones para crear un efecto de fondo genial para mi proyecto KaoCards:

Entonces, ahora sabes cómo animar gradientes en React Native, y un poco más sobre cómo funciona Animated. ¿Qué otras propiedades crees que puedes animar?

Gracias a Jason Brown por proporcionar la información clave. Todo lo que aprendí sobre animar cosas en React Native lo aprendí de él. Asegúrate de seguirlo en Twitter y mira su curso React Native Animations.