Las animaciones son parte importante de cualquier aplicación ya que permiten ofrece una mejor experiencia de uso siendo utilizadas como feedback para las acciones del usuario.
React Native ofrece una API para trabajar con animaciones directamente utilizando "just javascript"
En este post revisaremos como utilizar esta característica para crear tus propias animaciones!.
TLDR: Puedes ver este contenido en una video lección en egghead
La API Animated
React Native ofrece dos API complementarias: Animated
para un control granular de valores específicos y LayoutAnimation
para efectos animados globales en transacciones del layout.
La API Animated
fue diseñada para ofrecer control granular para crear diferentes patrones de interacción y con la mejor performance posible, es una api declarativa que permite control de inicio y fin de una animación.
Esta API exporta seis componentes para animar, pero también permite crear tu propio componente utilizando Animated.createAnimatedComponent()
.
Los componentes animados por defecto son: View
, Text
, Image
, ScrollView
, FlatList
y SectionList
Así mismo, Animated
ofrece métodos para controlar los valores que estás animando como Animated.timing
y Animated.spring
y otros que permiten componer animaciones como: Animated.parallel
, Animated.sequence
, Animated.delay
y Animated.loop
.
Primero vamos a revisar algunos de estos métodos:
Animated.timing y Animated.spring
Estos métodos permiten definir una animación, timing
permite definir un tiempo para ejecutar la animación y spring
utiliza un modelo físico para determinar la velocidad para ejecutar la animación, es decir, no es controlado por el tiempo.
Ambos métodos tienen una api similar aceptando casi los mismos parámetros
Revisemos un ejemplo
https://snack.expo.io/@matiasfh/example-translate-animation
En este ejemplo podemos ver dos elementos y dos animaciones, una con timing
y la otra con spring
.
Revisemos el código.
Lo primero que podemos ver dentro de la definicion de App
es el uso de React.useRef()
const translateAnimationTiming = React.useRef(new Animated.Value(0)).current
Aquí utilizamos useRef
para mantener una referencia a un valor sin necesidad de emitir un cambio de estado provocando un re-renderizado del componente, dentro del ref
creamos un valor para animar utilizando new Animated.Value(0)
iniciando que el valor inicial será 0, luego definimos la función que iniciará la animación, en este caso es un manejador para el evento click de los botones
const timingAnimation = () => {
Animated.timing(translateAnimationTiming, {
toValue: 250,
duration: 600,
useNativeDriver: true,
}).start()
}
Esta función declara y ejecuta la animación timing
. El primer argumento es el valor que se animará y luego recibe un objeto de configuración toValue
que declara que se animará hasta obtener el valor 250 en un tiempo duration: 600
(milisegundos). y definimos que se usará el driver nativo. Este último argumento es requerido por React Native como true
or false
.
Sólo algunos valores pueden ser animados utilizando el driver nativo, tal como se describe en este post de la documentación oficial, los valores animables por el driver nativo son todos aquellos “no relacionados con el layout”, es decir no puedes animar nativamente (pero si al utilizar useNativeDriver: false
) propiedades de flexbox, tamaños (width, height) o posiciones.
En este ejemplo también hay otra función que ejecuta la animación utilizando spring
const timingAnimation = () => {
Animated.spring(translateAnimationTiming, {
toValue: 250,
useNativeDriver: true,
}).start()
}
`
El método spring solo recibe el valor al cual se quiere animar (sin tiempo).
Puedes ver la diferencia entre ambas animaciones en el ejemplo de Snack.
Por cierto, en ambos casos se hizo una llamada al método start()
para iniciar la animación. start()
puede recibir un argumento. Un callback que es ejecutado cuando la animación terminó. Si la animación termino de forma correcta el callback será invocado con el argumento {finished:true}
, en caso contrario, si la animación, termino de forma errónea, o no se pudo completar (por ejemplo, por alguna interrupción al re-renderizar), el callback recibirá el parámetro {finished:false}
Componentes animados
Otro punto importante del ejemplo es el uso de componentes animados, en este caso Animated.View
este es un componente ofrecido por la API Animated que tiene el mismo comportamiento y props que el View
normal, pero contiene la lógica necesaria para efectuar los cambios en los estilos determinados por la función de animación.
javascript
<Animated.View
style={[
styles.circle,
animatedStyleTiming,
]}
/>
La animación es en el fondo, una modificación a alguna propiedad del estilo del componente, en este caso animatedStyleTiming
que para este ejemplo está definido como
javascript
const animatedStyleTiming = {
transform: [{ translateX: translateAnimationTiming}]
}
Este style, define la propiedad transform para indicar que se modificará la posición en X
del elemento.
Easing
Easing functions o funciones de aceleración especifican la forma o monto del cambio de un parámetro sobre durante el tiempo.
Los objetos, en la vida real no inician o detienen su movimiento de forma abrupta, y casi nunca se mueven a una velocidad constante.
React Native ofrece varias funciones de aceleración para aplicar en nuestras animaciones, para su uso simplemente debes importar el objeto Easing
, como en el siguiente ejemplo
https://snack.expo.io/@matiasfh/rn-easing-examples
En este pequeño proyecto puedes ver la aplicación de las diferentes funciones de aceleración disponibles
javascript
import { Easing } from 'react-native';
...
...
Animated.timing(animatedValue, {
...
easing: Easing.ease
}).start()
Para aplicar una función de aceleración a tu animación solo debes definir la propiedad easing
en la declaración de la animación.
Interpolation
Otro método que React Native dispone para controlar nuestras animaciones es la interpolación.
Cada propiedad definida para animar puede pasar por un proceso de interpolación primero, este proceso crea un mapa de entradas y salidas inputRange
y ouputRange
.
Esto te permite utilizar tu valor de animación varias veces incluso si solo está definido como un valor entre 0
y 1
al esquematizar tu rango de valores con un rango de la propiedad que quieres animar.
Vamos un ejemplo y animemos dos propiedades diferentes de dos componentes.
https://snack.expo.io/@matiasfh/rn-animation-interpolation-example
En este ejemplo tenemos dos componentes animados. Un circulo rojo que se mueve hacia la derecha y un circulo azul que “desaparece” cambiando su opacidad, pero solo tenemos la definición de un valor de animación
javascript
const animatedValue = react.useRef(new Animated.Value(0)).current
Valor de animación que comienza en 0 y que manipularemos para que cambie siempre entre valores 0 y 1.
También se definen dos interpolaciones translateInterpolation
que genera un mapa de 0 a 0 y 1 a 250. Y opacityInterpolation
que crea el mapa reverso 0 -> 1, y 1 -> 0. Indicando que cuando el valor de animación sea 0, el valor utilizado por la interpolación será 1
.
javascript
const translateInterpolation = animatedValue.interpolate({
inputRange: [0,1],
outputRange:[0,250]
})
const opacityInterpolation = animatedValue.interpolate({
inputRange: [0,1],
outputRange:[1,0]
})
También se modifica la función de animación para indicar que el valor de cambio será toValue: 1
javascript
const animation = () => {
animatedValue.setValue(0)
Animated.timing(animatedValue, {
toValue: 1,
duration: 600,
useNativeDriver: true,
}).start()
}
Entonces al hacer click en el botón Animate ambos componentes son animados, uno se mueve 250px
a la derecha mientras el otro cambia su opacidad de 1 a 0.
Conclusión
React Native provee de un control granular a la hora de crear animaciones permitiendo que sea solo tu imaginación el limite para definir como quieres que tu interfaz se comporte.
Para poder animar componentes necesitas utilizar los componentes animados provistos en el objeto Animated
y luego definir un valor de animación utilizando useRef
. Este valor de animación es después utilizado como parámetro para la función de animación que quieres utilizar como timing
o spring
.
Además ofrece una forma de control aún mas detallada como la interpolación, que permite crear un mapa de valores pudiendo reutilizar el valor de animación como se desee.
Top comments (0)