How to listen to value change in react-native-reanimated?
Asked Answered
F

3

7

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 ?

Friary answered 12/2, 2020 at 10:46 Comment(4)
any updates on this?Striking
Unfortunately Still I couldnt find a way for thatFriary
@Friary Have you checked this? software-mansion.github.io/react-native-reanimated/…Teniers
@Teniers according to the description, it seems to be a different thingStriking
S
18

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?

Striking answered 3/3, 2020 at 14:23 Comment(5)
didbt work as I want, please see once again my questionFriary
@Friary sorry to hear it. I'll add a minimal code example, maybe we don't understand each other :)Striking
Thank you very much, could you please let me know where the call function comes from ???Friary
Thank you very much, I am getting this error after updating as your code: Attempt to invoke virtual method 'double.java.lang.Double.doubleValue()' on a null object referenceFriary
Also I am updating only the cx like this circleSVG.current.setNativeProps({ cx: circleRadius.value.toString() }); so in your code what will be put to `cx' ?Friary
Y
3
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;

Ybarra answered 5/11, 2020 at 10:51 Comment(2)
as you can see in my code, I use useCode and call to change textValue smoothly.Ybarra
How can i implement it with Reanimated V2 :(?Iconoclast
L
1

Reanimated is meant to be a declarative API that allows you to run more advanced animations and thus complex logic on the native thread.

The reason something similar to addListener is not implemented is because it would require unnecessary messages between the native and JS thread. So rather than using a listener and setNativeProps to update the cx property of your circle, it would be best to use an 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}
/>
Lacilacie answered 21/5, 2020 at 19:15 Comment(2)
thank you, your code is same my code, so could you please show me whats your solutionFriary
Could you elaborate on your use case or add more of your code to the question? I'm not sure how or what is updating the AnimatedValue circleRadiusLacilacie

© 2022 - 2024 — McMap. All rights reserved.