react-nativeexporeact-native-reanimatedreact-native-reanimated-v2

How to animate expo-linear-gradient with reanimated?


I am using react-native-reanimated and want to animate the colors of my expo-linear-gradient. Unfortunately, nothing changes. I also created a Expo Snack.

import * as React from 'react';
import { View, Button } from 'react-native';
import Animated, {
  interpolateColor,
  useAnimatedProps,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

import { LinearGradient } from 'expo-linear-gradient';

const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient);

export default function App() {
  const colorsValue = useSharedValue(1); 

  const animatedProps = useAnimatedProps(() => {
    return {
      colors: [
        interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#000000']),
        interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#00ff00']),
      ],
    };
  });

  return (
    <View>
      <AnimatedLinearGradient
        animatedProps={animatedProps}
        style={{ height: 400, width: '100%' }}
      />
      <Button
        title="Change colors"
        onPress={() => (colorsValue.value = withTiming(0, { duration: 2000 }))}
      />
    </View>
  );
}

Am I using animatedProps wrongly here? Any help would greatly be appreciated.


Solution

  • unfortunately, I'm not sure you can do that. You're using correctly the useAnimatedProps hook, but usually it doesn't work for all properties.

    If you want to achieve this type of animation, I highly recommend you to try the LinearGradient component from @shopify/react-native-skia package.

    You can easily reuse the same logic, but with the Skia values:

     const colorsValue = useSharedValue(1); 
     const skiaFirstColor = useValue(0); 
     const skiaSecondColor = useValue(0);
    
     useSharedValueEffect(() => {
       skiaFirstColor.current = interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#000000']);
       skiaSecondColor.current = interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#00ff00']);
     }, colorsValue); // you can pass other shared values as extra parameters
    
     const colors = useComputedValue(() => {
      return [skiaFirstColor.current, skiaSecondColor.current]
     }, [skiaFirstColor, skiaSecondColor])
    
    return (<... 
      <Canvas>
        <LinearGradient colors={colors} /> 
      </Canvas>
    </>)
      
    

    Let me know if it helps.