How to make an Endless Road Animation in React Native

869 Views Asked by At

In my app, I want to have a road, that is animated to look like it is moving. To do this, I have several Views that make up the lines in the center of the road, and want them to translate on a loop to make it look like the road is moving, similar to this. However, I am not sure how best to do this.

I have four road line views, and they are currently all set to translate to the left on an endless loop. However, this results in the lines jumping back to their start position once they have completed the translation, whereas I want it on a smooth loop. Any ideas how to do this?

This is what my code currently looks like:

const Road = () => {
    const translation = useRef(new Animated.Value(0)).current;

    useEffect(() => {
        Animated.loop(
            Animated.timing(translation, {
                toValue: -150,
                useNativeDriver: true,
            })
        ).start();
        
    }, []);

    return (
        <View style={styles.roadContainer}>
            <View style={styles.lineContainer}>                
                <Animated.View
                    style={{
                        ...styles.roadLine,
                        transform: [{ translateX: translation }],
                    }}
                ></Animated.View>
                <Animated.View
                    style={{
                        ...styles.roadLine,
                        transform: [{ translateX: translation }],
                    }}
                ></Animated.View>
                <Animated.View
                    style={{
                        ...styles.roadLine,
                        transform: [{ translateX: translation }],
                    }}
                ></Animated.View>
                <Animated.View
                    style={{
                        ...styles.roadLine,
                        transform: [{ translateX: translation }],
                    }}
                ></Animated.View>
                
            </View>
        </View>
    );
};
2

There are 2 best solutions below

0
On

Not sure if this is the best approach, but it is what I have come up with for now and it seems to work. All I did was work out the translation value so that each lines finishing position was the starting position of the line to its left, so that when the animation reset, it would look like there was no change.

I also added Easing.linear to the animation, to make the loop appear seamless.

useEffect(() => {
        Animated.loop(
            Animated.timing(translation, {
                toValue: -wp("46%"),
                useNativeDriver: true,
                duration: 200,
                easing: Easing.linear,
            })
        ).start();
        
    }, []);
0
On

Snack example

The main parts of this solution:

const startAnimation = () => {
  roadAnimation.start(() => {
    roadAnimation.reset();
    startAnimation();
  });
};

useEffect(() => {
  startAnimation();
}, []);

We call startAnimation when component mounts. When animation finishes, we reset it and start it again to create a loop. Also we use easing: Easing.linear, to make animation loop appear to be endless.