我用Animated
和react-native
的{{1}}创建了一个简单的动画。
这很好地完成了工作,
但是现在我切换到react-native-svg
,因为在他们的网站上阅读的内容比react-native-reanimated
的{{1}}恢复速度快。
但是在这里我遇到了一个问题,那就是我找不到函数Animated
来监听值的变化。
来自react-native
的带有addListener
的代码:
Animated
如何在{strong> react-native
中实现以上const circleRadius = new Animated.value(100);
circleRadius.addListener( circleRadius => {
circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() });
});
功能?
答案 0 :(得分:9)
您可以使用Animated.call
实现类似的行为。 Here是有关该主题的不错的教程。
编辑:
例如,要监听circleRadius
的更改,可以使用以下代码:
import { call, useCode } from 'react-native-reanimated'
useCode(() => {
return call([circleRadius], (circleRadius) => {
console.log(circleRadius)
})
}, [circleRadius])
它可以做什么?
答案 1 :(得分:2)
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;
答案 2 :(得分:1)
Reanimated是声明性的API,使您可以在本地线程上运行更高级的动画,从而运行复杂的逻辑。
之所以未实现类似于addListener
的原因,是因为它在本机线程和JS线程之间需要不必要的消息。因此,与其使用侦听器和setNativeProps
来更新圈子的cx
属性,不如使用AnimatedNode
。
const circleRadius = new Animated.value(100);
circleRadius.addListener( circleRadius => {
circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() });
});
import { Circle } from 'react-native-svg';
// must make Circle compatible with Animated Values
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
// then within your svg
<AnimatedCircle
// ... add other props
cx={circleRadius}
/>
答案 3 :(得分:0)
绝对应该使用useCode
和call
。有一个与此相关的问题:
https://github.com/software-mansion/react-native-reanimated/issues/1417