Mastering React Native Animations — A Simple Spring Animation for a Map Icon
Animations can greatly enhance the user experience of your React Native applications. They add a touch of interactivity and polish that can make your app feel more dynamic and engaging. In this blog, we’ll explore how to use React Native’s Animated
library to create smooth animations, with a straightforward spring animation applied to a map icon.
Before diving into the code, let’s understand the three key components of this React Native animation: initialization, spring animation, and JSX implementation.
1. Initialisation
const animation = useMemo(() => new Animated.Value(10), []);
useMemo(() => ...)
:useMemo
is a hook in React that memoizes (caches) the result of a function and returns it. It takes two arguments: a function and a dependency array.() => new Animated.Value(10)
: This is the function thatuseMemo
is memoizing. It creates a new instance ofAnimated.Value
with an initial value of10
.[]
: This is the dependency array. When an empty array is provided, it means that the memoized value (in this case, the animated value) will not change as long as the component is mounted. It effectively runs the memoized function (in this case, creating the animated value) only once when the component mounts.
2. The Spring Animation
Animated.spring(animation, {
toValue: 30,
duration: 2000,
friction: 1,
tension: 1,
useNativeDriver: true
}).start();
This line of code is responsible for setting up and starting the animation. It uses the Animated.spring
method to create a spring-based animation.
animation
: This is the animated value that the animation is applied to. In our case, it's an instance ofAnimated.Value
that starts at 10.{ toValue: 30, duration: 2000, friction: 1, tension: 1, useNativeDriver: true }
: These are the configuration options for the animationtoValue
: This is the final value that the animated property (in this case,animation
) will reach. In this code, it's set to 30, meaning the animation will transition from 10 to 30.duration
: This is the duration of the animation in milliseconds. Here, it's set to 2000 milliseconds (or 2 seconds).friction
: This controls how "loose" or "tight" the spring feels. A higher value will make the animation feel more damped. Here, it's set to 1.tension
: This controls how "stiff" the spring is. A higher value will make the animation feel more stiff. Here, it's set to 1.useNativeDriver
: This is a performance optimization. When set totrue
, the animation is offloaded to the native thread, which can result in smoother animations. It's generally recommended to set this totrue
..start()
: This method actually starts the animation.
The animation is wrapped in a useEffect
hook. It determines when the animation should start. The second argument [animation]
is the dependency array. This means that whenever the value of animation
changes, the effect (in this case, starting the animation) will be triggered.
Since animation
is a dependency and it's only created once ( as it is inside a useMemo
), this effect will run once when the component mounts. This ensures that the animation starts when the component is first rendered.
3. JSX implementation
<Animated.View style={{ transform: [{ translateY: animation }] }}>
<Image
style={{ width: 150, height: 150 }}
source={require("../assets/map.png")}
/>
</Animated.View>
This is JSX code that renders an animated view. Let’s break down the important parts:
<Animated.View>
: This is a special animated version of theView
component provided by React Native. It's used for animating elements.style={{ transform: [{ translateY: animation }] }}
: This is setting the style of theAnimated.View
. Thetransform
property is an array of transformations to be applied to the view. In this case, it's using thetranslateY
transform.translateY
is a translation along the vertical axis. It moves the view up or down. The value is determined by theanimation
variable, which is an animated value.animation
is used here to drive the animation. As the value ofanimation
changes (animated from 10 to 30), it will cause the view to smoothly transition from its initial position to the final position.
Complete code:
const animation = useMemo(() => new Animated.Value(10), []);
useEffect(() => {
Animated.spring(animation, {
toValue: 30,
duration: 2000,
friction: 1,
tension: 1,
useNativeDriver: true
}).start();
}, [animation]);
return (
<Animated.View style={{ transform: [{ translateY: animation }] }}>
<Image
style={{ width: 150, height: 150 }}
source={require("../assets/map.png")}
/>
</Animated.View>
);
For a complete working example of the above code discussed, you can explore this sandbox. This sandbox contains the entire code, allowing you to see the animations in action and experiment with the parameters to further understand their effects.