dereck quock

Looping Opacity Animation in React Native

1 min read

I needed to animate a red dot similar to how a recording light flashes. Kinda like this 👇

CSS Keyframes make it as easy as pie 🥧

@keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.blinking-dot {
width: 30px;
height: 30px;
background: rgba(179, 0, 0, 0.8);
border-radius: 15px;
animation: blink 1s infinite;
}

A blinking dot in React Native requires a little more work. Animations are usually implemented using react-native-reanimated. With the help of react-native-redash from William Candillon, who does the Can it be done in React Native videos on YouTube, animating this blinking dot isn't that bad. Using the loop() function with the boomerang option set to true, the opacity will bounce back and forth from 0 to 1 🦘

import Svg, { Circle } from 'react-native-svg';
import Animated, { Easing } from 'react-native-reanimated';
import { loop, mix } from 'react-native-redash';
const { set, useCode, Value } = Animated;
function BlinkingDot() {
const animation = new Value(0);
useCode(
() =>
set(
animation,
loop({
duration: 1000,
easing: Easing.inOut(Easing.ease),
// the animation goes from 0 to 1 and then
// from 1 to 0 in the next cycle
boomerang: true,
autoStart: true,
})
),
[animation]
);
// Interpolate the node from 0 to 1 without clamping
const opacity = mix(animation, 0.1, 1);
return (
<Animated.View style={{ opacity }}>
<Svg style={styles.circle} viewBox="0 0 100 100">
<Circle cx="50" cy="50" r="50" fill={Colors.red} fillOpacity="1" />
</Svg>
</Animated.View>
);
}

React Native Reanimated uses a declarative API, so it's a lot easier to understand what's going on. Animations are performed in steps, which is very similar to how keyframe animations are executed. This is great because it lowers the barrier of entry for developers getting into React Native.

UPDATE: Reanimated 2

With Reanimated 2, it's much simpler and composable out of the box. We can define the animated opacity by composing together the higher-order animation functions withTiming, which returns the animation, and withRepeat, which takes in the animation to repeat.

import Svg, { Circle } from 'react-native-svg';
import Animated, {
Easing,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';
function BlinkingDot() {
const opacity = useSharedValue(0);
// Set the opacity value to animate between 0 and 1
opacity.value = withRepeat(
withTiming(1, { duration: 1000, easing: Easing.ease }),
-1,
true
);
const style = useAnimatedStyle(() => ({ opacity: opacity.value }), []);
return (
<Animated.View style={style}>
<Svg style={styles.circle} viewBox="0 0 100 100">
<Circle cx="50" cy="50" r="50" fill={Colors.red} fillOpacity="1" />
</Svg>
</Animated.View>
);
}