React-native-reanimated: v2 How does one use color interpolation and withTiming hook

Created on 30 Aug 2020  Β·  9Comments  Β·  Source: software-mansion/react-native-reanimated

Description

I am using Android Studio's adb to test my app.
As per code, when the button is clicked, i would like to change the backgroundColor of the View "interpolate-ly" from tomato to teal.

  1. Using the code directly below will not change the color, but when Fast Reload is initiated from my code editor, the color did change to teal.
  2. Using the commented backgroundColorInterpolation to style={[anyOtherStyle, backgroundColorInterpolation]} will crash my app upon entering the screen

Is that not how it works or has i been implementing them the wrong way?

Code

import {  Button,  } from 'react-native';
import Animated ,{
        useAnimatedStyle,
    useSharedValue,
    withTiming,
    interpolateColors
} from 'react-native-reanimated';

function testScreen(){

    const colorAnim = useSharedValue(0)

    const backgroundColorInterpolation = interpolateColors(colorAnimDerivedValue.value, {
        inputRange:[0,15],
        outputColorRange:["tomato","teal"]
    }) 

       // tried to use the one below, but app would crash without throwing any error

    // const backgroundColorInterpolation = useAnimatedStyle(() => {
       //   const interpolation = interpolateColors(colorAnim.value, {
       //         inputRange:[0,15],
       //         outputColorRange:["tomato","teal"]
       //     }) 

    //  return {
    //    backgroundColor: interpolation
    //  };
    // });

    return (
            <Animated.View style={{   flex:1, backgroundColor:backgroundColorInterpolation}}>
                             <Button 
                                     onPress={() => {
                                         colorAnim.value = withTiming(15, {
                                             duration: 1000,
                                     });
                                    }
                              }/>
              </Animated.View>
    );
};

export default testScreen

Package versions

  • React: 16.13.1
  • React Native:0.63.0
  • React Native Reanimated:^2.0.0-alpha.5
❓Question 🏠 Reanimated2

Most helpful comment

Hi there, in order to pass some animated values to the styles, you need to use useAnimatedStyle hook. Passing values directly is no longer supported with Reanimated v2 API (You can still use Reanimated v1 with new Value and all the cond, set, add etc though).

This particular example @atcode-soft provided is not working because the provided interpolateColor API is only compatible with Reanimated v1.

Unfortunately, there is no API for that in the core, but you can use the one react-native-redash provides.

import Animated, {
  useSharedValue,
  useAnimatedScrollHandler,
  useAnimatedStyle
} from "react-native-reanimated";
import { interpolateColors } from "react-native-radash";

const ComponentName = () => {
  const scrollOffset = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: event => {
      scrollOffset.value = event.contentOffset.x;
    }
  });

  const backgroundStyles = useAnimatedStyle(() => {
    // make sure to run any interpolations inside the worklet
    // callback of useAnimatedStyle is a worklet
    // but also it knows you has access the scrollOffset value
    // so now it will re-run on each scroll change change

    // usage https://wcandillon.gitbook.io/redash/colors#interpolatecolor
    const backgroundColor = interpolateColors(
      scrollOffset.value,
      [0, width, width * 2, width * 3],
      ["#BFEAF5", "#BEECC4", "#FFE4D9", "#FFDDDD"]
    );
  }, []);

  return (
    <View style={styles.container}>
      <Animated.View style={[styles.slider, backgroundStyles]}>
        <Animated.ScrollView
          horizontal
          snapToInterval={width}
          decelerationRate="fast"
          showsHorizontalScrollIndicator={false}
          bounces={false}
          onScroll={scrollHandler}
          scrollEventThrottle={1}
        >
          ...
        </Animated.ScrollView>
      </Animated.View>
    </View>
  );
};

All 9 comments

Same issue with React Native Reanimated:^2.0.0-alpha.6

function Lol() {
  const progress = useSharedValue(2);

  return (
    <View>
      <Test progress={progress} />
      <Button
        title="lol"
        onPress={() =>
          (progress.value = withTiming(Math.random(), {
            duration: 1000,
            easing: Easing.inOut(Easing.cubic),
          }))
        }
      />
    </View>
  );
}
const Test = ({progress}) => {
  const animatedTextStyles = useAnimatedStyle(() => {
    return {
      width: progress.value * 100,
    };
  });
  const backgroundStyle = useAnimatedStyle(() => {
    const backgroundColorInterpolation = interpolateColors(progress.value, {
      inputRange: [0, 2],
      outputColorRange: ['#000000', '#FFFFFF'],
    });

    return {
      backgroundColor: backgroundColorInterpolation,
    };
  });

  return (
    <Animated.View
      style={[
        {height: 50, backgroundColor: '#000000'},
        animatedTextStyles,
        backgroundStyle,
      ]}
    />
  );
};

Any update on this? I'm also trying to achieve background color animations for my scroll view but it doesn't seem to be working

import React from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';
import Animated, {
  event,
  useValue,
  interpolateColors,
  useAnimatedStyle,
  withTiming,
  useSharedValue,
  useAnimatedScrollHandler,
} from 'react-native-reanimated';

const {width} = Dimensions.get('window');
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  slider: {
    borderBottomRightRadius: 75,
  },
  footer: {
    flex: 1,
  },
});

const ComponentName = () => {
  const scrollOffset = useSharedValue(0);
  const backgroundColor = interpolateColors(
    scrollOffset.value,
    {
      inputRange: [0, width, width * 2, width * 3],
      outputColorRange:['#BFEAF5', '#BEECC4', '#FFE4D9', '#FFDDDD']
    }
  );

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: event => {      
      scrollOffset.value = event.contentOffset.x;
    },
  });
  return (
    <View style={styles.container}>
      <Animated.View style={[styles.slider, {backgroundColor}]}>
        <Animated.ScrollView
          horizontal
          snapToInterval={width}
          decelerationRate="fast"
          showsHorizontalScrollIndicator={false}
          bounces={false}
          onScroll={scrollHandler}
          scrollEventThrottle={1}
          >
           ...
        </Animated.ScrollView>
      </Animated.View>
    </View>
  );
};

export default ComponentName;

Retried on ^2.0.0-alpha.6, doesn't seem to work yet

Hi there, in order to pass some animated values to the styles, you need to use useAnimatedStyle hook. Passing values directly is no longer supported with Reanimated v2 API (You can still use Reanimated v1 with new Value and all the cond, set, add etc though).

This particular example @atcode-soft provided is not working because the provided interpolateColor API is only compatible with Reanimated v1.

Unfortunately, there is no API for that in the core, but you can use the one react-native-redash provides.

import Animated, {
  useSharedValue,
  useAnimatedScrollHandler,
  useAnimatedStyle
} from "react-native-reanimated";
import { interpolateColors } from "react-native-radash";

const ComponentName = () => {
  const scrollOffset = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: event => {
      scrollOffset.value = event.contentOffset.x;
    }
  });

  const backgroundStyles = useAnimatedStyle(() => {
    // make sure to run any interpolations inside the worklet
    // callback of useAnimatedStyle is a worklet
    // but also it knows you has access the scrollOffset value
    // so now it will re-run on each scroll change change

    // usage https://wcandillon.gitbook.io/redash/colors#interpolatecolor
    const backgroundColor = interpolateColors(
      scrollOffset.value,
      [0, width, width * 2, width * 3],
      ["#BFEAF5", "#BEECC4", "#FFE4D9", "#FFDDDD"]
    );
  }, []);

  return (
    <View style={styles.container}>
      <Animated.View style={[styles.slider, backgroundStyles]}>
        <Animated.ScrollView
          horizontal
          snapToInterval={width}
          decelerationRate="fast"
          showsHorizontalScrollIndicator={false}
          bounces={false}
          onScroll={scrollHandler}
          scrollEventThrottle={1}
        >
          ...
        </Animated.ScrollView>
      </Animated.View>
    </View>
  );
};

@terrysahaidak interpolateColor from redash returns an interger so I had to convert it to a color to make it working.

  const backgroundStyles = useAnimatedStyle(() => {
    const backgroundColor = interpolateColor(
      scrollOffset.value,
      [0, width, width * 2, width * 3],
      ['#BFEAF5', '#BEECC4', '#FFE4D9', '#FFDDDD']
    );
    const color = '#' + (backgroundColor & 0x00ffffff).toString(16).padStart(6, '0');

    return {backgroundColor: color};
  });

I'm not sure if this is how I'm supposed to do it.

also this library is also converting the color to an integer if the platform is android which is not working
https://github.com/wcandillon/react-native-redash/blob/fb92e506d8d3f1c40ef32ae50e93a0378e6ffaa9/src/Colors.ts#L43-L59

@terrysahaidak interpolateColor from redash returns an interger so I had to convert it to a color to make it working.

  const backgroundStyles = useAnimatedStyle(() => {
    const backgroundColor = interpolateColor(
      scrollOffset.value,
      [0, width, width * 2, width * 3],
      ['#BFEAF5', '#BEECC4', '#FFE4D9', '#FFDDDD']
    );
    const color = '#' + (backgroundColor & 0x00ffffff).toString(16).padStart(6, '0');

    return {backgroundColor: color};
  });

I'm not sure if this is how I'm supposed to do it.

also this library is also converting the color to an integer if the platform is android which is not working
wcandillon/react-native-redash@fb92e50/src/Colors.ts#L43-L59

In React Native each color is represented as a number. It's something React Native understands so no need for conversion it to string.

I just checked on my project that code and it works.

Could you post the whole code so we can find the case?

That worked. I appreciate your help.

@terrysahaidak interpolate from redash seems to return undefined for me. Can you confirm if it's working or maybe I'm doing something wrong

  const width = useWindowDimensions().width;
    5
✹   6     const x = useSharedValue(0);
✚   7     const scrollHandler = useAnimatedScrollHandler({
✚   8         onScroll: (event) => {
✚   9             x.value = event.contentOffset.x;
✚  10         },
✚  11     });
✚  12
✚  13     const bgStyle = useAnimatedStyle(() => {
✚  14         const bgC = interpolateColor(
✚  15             x.value,
✚  16             [0, width, width * 2, width * 3],
✚  17             ["#BFEAF5", "#BEECC4", "#FFE4D9", "#FFDDDD"]
✚  18         );
✚  19         console.log(bgC);
✚  20
✚  21         return {
✚  22             backgroundColor: bgC ? bgC : "yellow",
✚  23         };
✚  24     });

console

undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined

Just adding it here, currently got the issue handled with the addition of interpolateColor in version 2.0.0-alpha.8, though now I am now using version 2.0.0-alpha.9, with pretty much the same implementation like the example I gave on the first thread. Thanks for everyone who replied!

Was this page helpful?
0 / 5 - 0 ratings