如何聆听react-native-reanimated中的价值变化?

时间:2020-02-12 10:46:02

标签: javascript react-native react-native-svg react-native-reanimated

我用Animatedreact-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() }); }); 功能?

4 个答案:

答案 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)

绝对应该使用useCodecall。有一个与此相关的问题: https://github.com/software-mansion/react-native-reanimated/issues/1417