I have created a simple animation with Animated
from react-native
with react-native-svg
.
This do the jobs well,
But Now I switched to react-native-reanimated
cuz I read on their website that reanimated is faster than Animated
from react-native
.
But here I faced with a problem, and that is I cant find function addListener
to listen to the value changes.
Code with Animated
from react-native
:
const circleRadius = new Animated.value(100);
circleRadius.addListener( circleRadius => {
circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() });
});
How can I implement above addListener
function in react-native-reanimated
?
To get the current value of Animated. Value with React Native, we call addListener on the animated value object. to call spinValue. addListener with a callback to get the current value of the animated value from the value property.
Reanimated 2 is based on a new API named animation worklets. These are JavaScript functions that run on the UI thread independently from the JavaScript thread. These functions can be declared as a worklet via the worklet directive.
You can achieve similar behavior using Animated.call
. Here is a nice tutorial about the subject.
Edited:
For example, to listen to circleRadius
changes, you could use this code:
import { call, useCode } from 'react-native-reanimated'
useCode(() => {
return call([circleRadius], (circleRadius) => {
console.log(circleRadius)
})
}, [circleRadius])
Does it do what you want?
import React, { FC, useRef } from 'react';
import { StyleSheet, TextInput, View } from 'react-native';
import Svg, { G, Circle } from 'react-native-svg';
import Animated, { call, Easing, interpolate, useCode } from 'react-native-reanimated';
import { timing } from 'react-native-redash';
interface DonutChartProps {
percentage: number;
radius?: number;
strokeWidth?: number;
duration?: number;
color?: string;
delay?: number;
textColor?: string;
max?: number;
}
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
const DonutChart: FC<DonutChartProps> = ({
percentage,
radius = 40,
strokeWidth = 10,
duration = 500,
color = 'tomato',
textColor,
max = 100,
}) => {
const inputRef = useRef<TextInput>(null);
const halfCircle = radius + strokeWidth;
const circumference = 2 * Math.PI * radius;
const maxPercentage = (100 * percentage) / max;
const animation = timing({
from: 0,
to: 1,
duration,
easing: Easing.inOut(Easing.linear),
});
const strokeDashoffset = interpolate(animation, {
inputRange: [0, 1],
outputRange: [circumference, circumference - (maxPercentage * circumference) / 100],
});
const textValue = interpolate(animation, {
inputRange: [0, 1],
outputRange: [0, Math.round(percentage)],
});
useCode(
() => [
call([textValue], ([textValue]) => {
if (inputRef.current) {
inputRef.current.setNativeProps({
text: `${Math.round(textValue)}`,
});
}
}),
],
[textValue]
);
return (
<View>
<Svg width={radius * 2} height={radius * 2} viewBox={`0 0 ${halfCircle * 2} ${halfCircle * 2}`}>
<G rotation="-90" origin={`${halfCircle}, ${halfCircle}`}>
<Circle
cx="50%"
cy="50%"
stroke={color}
strokeWidth={strokeWidth}
r={radius}
fill="transparent"
strokeOpacity={0.2}
/>
<AnimatedCircle
cx="50%"
cy="50%"
stroke={color}
strokeWidth={strokeWidth}
r={radius}
fill="transparent"
strokeDasharray={circumference}
strokeDashoffset={strokeDashoffset}
strokeLinecap="round"
/>
</G>
</Svg>
<AnimatedTextInput
ref={inputRef}
underlineColorAndroid="transparent"
editable={false}
defaultValue="0"
style={[
StyleSheet.absoluteFillObject,
{ fontSize: radius / 2, color: textColor ?? color, fontWeight: '900', textAlign: 'center' },
]}
/>
</View>
);
};
export default DonutChart;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With