【问题标题】:How to listen to value change in react-native-reanimated?如何在 react-native-reanimated 中聆听价值变化?
【发布时间】:2020-05-27 21:44:34
【问题描述】:

我用Animatedreact-nativereact-native-svg 创建了一个简单的动画。

这可以很好地完成工作,

但现在我切换到react-native-reanimated,因为我在他们的网站上看到,从react-native 恢复动画比Animated 快。

但是在这里我遇到了一个问题,那就是我找不到函数addListener 来监听值的变化。

Animated 的代码来自react-native

const circleRadius = new Animated.value(100);

circleRadius.addListener( circleRadius => {
       circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() });
});

如何在react-native-reanimated中实现上述addListener函数

【问题讨论】:

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


【解决方案1】:
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;

【讨论】:

  • 如您在我的代码中所见,我使用useCodecall 来平滑更改textValue。
  • 如何使用 Reanimated V2 实现它:(?
【解决方案2】:

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}
/>

【讨论】:

  • 谢谢,你的代码和我的代码一样,请问你的解决方案是什么
  • 您能否详细说明您的用例或在问题中添加更多代码?我不确定如何更新 AnimatedValue circleRadius
【解决方案3】:

您可以使用Animated.call 实现类似的行为。 Here 是一个很好的关于这个主题的教程。

已编辑:

例如,要监听circleRadius 的变化,您可以使用以下代码:

  import { call, useCode } from 'react-native-reanimated'

  useCode(() => {
    return call([circleRadius], (circleRadius) => {
      console.log(circleRadius)
    })
  }, [circleRadius])

它做你想做的事吗?

【讨论】:

  • didbt 按我的意愿工作,请再次查看我的问题
  • @Muhammad 很遗憾听到这个消息。我将添加一个最小的代码示例,也许我们彼此不理解:)
  • 非常感谢,能否请您告诉我call函数的来源???
  • 非常感谢,更新为您的代码后出现此错误:尝试在空对象引用上调用虚拟方法'double.java.lang.Double.doubleValue()'
  • 另外,我只更新cx 这样的circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() }); 所以在你的代码中将把什么放到`cx' 中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-17
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多