React Native Pulse( Tinder inspired) Animation with Reanimated 2
Create Pulse animation with Reanimated 2
In this post, I m going to create and make a detailed explanation of how we can create pulse animation with Reanimated library.
Let's dive into the code.
First of all, I created a component named Pulse
, it's a circle
const Pulse = () => {
return <Animated.View style={styles.circle} />;
};
const styles = StyleSheet.create({
circle: {
width: 300,
borderRadius: 150,
height: 300,
position: 'absolute',
borderColor: '#e91e63',
borderWidth: 4,
backgroundColor: '#ff6090',
},
});
and inside the main App component, I used Image
and wrapped it with a container view.
Now we can add animation to the Pulse component. For the animation we use withTiming
and withRepeat
animation and useAnimatedStyle
hook.
// Create shared Value
const animation = useSharedValue(0);
// We repeatedly doing shared value from 0 to 1
useEffect(() => {
animation.value =
withRepeat(
withTiming(1, {
duration: 2000,
easing: Easing.linear,
}),
-1,
false
);
}, []);
// when component mount. scale the component from 0 to 1.
// also we used interpolate for decreasing opacity. 0.6 to 0
const animatedStyles = useAnimatedStyle(() => {
const opacity = interpolate(
offset.value,
[0, 1],
[0.6, 0],
Extrapolate.CLAMP
);
return {
opacity: opacity,
transform: [{ scale: offset.value }],
};
});
it's simple right? now we have one circle animation. but let's add one more feature.
When the user clicks the image add new animation to the view.
I create a state named pulse.
const [pulse, setPulse] = useState([1]);
and wrapped Image component with Pressable
<Pressable
style={styles.innerCircle}
onPress={() => {
setPulse((prev) => [...prev, Math.random()]);
}}>
<Image
style={styles.innerCircle}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/>
</Pressable>
It randomly adds a number to the pulse array. Then I use the map function to return multiple pulse components. I added it because I wanted newly added animations to be displayed only once.
{pulse.map((item, index) => (
<Pulse repeat={index === 0} />
))}
const Pulse = ({repeat }) => {
const animation = useSharedValue(0);
useEffect(() => {
animation.value = withDelay(
delay,
withRepeat(
withTiming(1, {
duration: 2000,
easing: Easing.linear,
}),
repeat ? -1 : 1,
false
)
);
}, []);
const animatedStyles = useAnimatedStyle(() => {
const opacity = interpolate(
animation.value,
[0, 1],
[0.6, 0],
Extrapolate.CLAMP
);
return {
opacity: opacity,
transform: [{ scale: animation.value }],
};
});
return <Animated.View style={[styles.circle, animatedStyles]} />;
};
That's it. Snack repo is here