Custom Animations

Custom Animation


After some effort, we finally implemented custom animation in v2, now we just need to implement a callback function of type TAnimationStyle and pass it to the customAnimation property of Carousel.

Prepare

type TAnimationStyle = (value: number) => Animated.AnimatedStyleProp<ViewStyle>;

This function will be called in each item and accepts a parameter value indicating the position of the current item relative to window. The following picture shows the relationship between value and position

Sketch File

After getting the value, we only need to describe how the item is displayed in the corresponding position, and the rest is handed over to Animated to execute.

ℹ️

Don't forget to set zIndex

Let's get started!

Here are a few examples.

Parallax

advanced-parallax

const animationStyle: TAnimationStyle = React.useCallback((value: number) => {
    'worklet';
 
    const zIndex = interpolate(value, [-1, 0, 1], [10, 20, 30]);
    const translateX = interpolate(
        value,
        [-1, 0, 1],
        [-PAGE_WIDTH * 0.5, 0, PAGE_WIDTH]
    );
 
    return {
        transform: [{ translateX }],
        zIndex,
    };
}, []);
 
<Carousel
    style={{ width: screen.width, height: 240 }}
    width={screen.width}
    data={[...new Array(6).keys()]}
    customAnimation={animationStyle}
    renderItem={({ index, animationValue }) => {
        return (
            <CustomItem
                key={index}
                index={index}
                animationValue={animationValue}
            />
        );
    }}
/>;
 
const CustomItem = ({ index, animationValue }) => {
    const maskStyle = useAnimatedStyle(() => {
        const backgroundColor = interpolateColor(
            animationValue.value,
            [-1, 0, 1],
            ['#000000dd', 'transparent', '#000000dd']
        );
 
        return {
            backgroundColor,
        };
    }, [animationValue]);
 
    return (
        <View style={{ flex: 1 }}>
            <SBItem key={index} index={index} style={{ borderRadius: 0 }} />
            <Animated.View
                pointerEvents="none"
                style={[
                    {
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                        bottom: 0,
                    },
                    maskStyle,
                ]}
            />
        </View>
    );
};

In order to implement some animation effects outside Carousel, such as MaskView, we pass the animation value calculated inside each Item to the outside through renderItem.

ScaleFadeInOut

scale-fade-in-out

const animationStyle: TAnimationStyle = React.useCallback((value: number) => {
    'worklet';
 
    const zIndex = interpolate(value, [-1, 0, 1], [10, 20, 30]);
    const scale = interpolate(value, [-1, 0, 1], [1.25, 1, 0.25]);
    const opacity = interpolate(value, [-0.75, 0, 1], [0, 1, 0]);
 
    return {
        transform: [{ scale }],
        zIndex,
        opacity,
    };
}, []);
 
<Carousel
    style={{
        width: screen.width,
        height: 240,
        justifyContent: 'center',
        alignItems: 'center',
    }}
    width={screen.width * 0.7}
    height={240 * 0.7}
    data={[...new Array(6).keys()]}
    customAnimation={animationStyle}
    renderItem={({ index }) => {
        return <SBItem key={index} index={index} />;
    }}
/>;