Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to make infinite animation in react native?

My cards here work from right to left with a nice animation. But when the animation rewinds, the card positions rewind and there is no infinite animation image. What I want is for the first card to enter again as the last card leaves the screen and infinity occurs. how do i do this? As you can see in the gif, the animation ends and I want the last element to exit from the left of the screen and the first element to enter again.

enter image description here

import React, { useEffect, useRef } from 'react';
import { Animated, StyleSheet, Text, View, Dimensions, Image } from 'react-native';

import anonim_icon from "../img/anonim.png";

const cardData = [
    { id: 0, title: "Feeling Happy" },
    { id: 1, title: "Feeling Calm" },
    { id: 2, title: "Feeling Angry" },
    { id: 3, title: "Feeling Sad" },
];

const App = () => {
    const translateX = useRef(new Animated.Value(width)).current;

    const Cards = ({ item, index }) => {
        return (
            <View style={styles.cards_con} key={index}>
                <Image
                    style={styles.cards_ico}
                    source={anonim_icon}
                    resizeMode="contain"
                />
                <Text style={styles.card_title}>{item.title}</Text>
            </View>
        );
    };

    useEffect(() => {
        const startAnimation = () => {
            translateX.setValue(width); // Animasyon başlangıç pozisyonu (sağ dışı)
            Animated.loop(
                Animated.sequence([
                    Animated.timing(translateX, {
                        toValue: -width * cardData.length, // Sol dışına çıkış
                        duration: 17000, // Hareket sĂĽresi
                        useNativeDriver: true,
                    }),
                ]),
            ).start();
        };

        startAnimation();
    }, [translateX, width]);

    return (
        <View style={styles.container}>
            <Animated.View
                style={{
                    flexDirection: 'row',
                    transform: [{ translateX }],
                }}
            >
                <View style={{ width: width * 3 }}/>
                {cardData.map((item, index) => (
                    <Cards key={index} item={item} index={index} />
                ))}
            </Animated.View>
        </View>
    );
};

const { width, height } = Dimensions.get('window');

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "#000",
    },
    cards_con: {
        flexDirection: "row",
        alignItems: "center",
        justifyContent: "space-around",
        backgroundColor: "#323232",
        height: height / 13,
        borderRadius: 10,
        marginHorizontal: 10,
        padding: 10,
        width: width / 1.7,
    },
    cards_ico: {
        width: 30,
        height: 30,
        borderRadius: 10,
    },
    card_title: {
        color: "#FFFFFF",
        marginLeft: 10,
        fontSize: 16,
    },
});

export default App;

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

here’s the modified code.

Changes I had to do to achieve your effect:

  1. Moves the cards to the left
  2. Instantly resets position to start
  3. Restarts the animation
  4. Added proper cleanup with stopAnimation() in the useEffect cleanup function
  5. Added a clipContainer with overflow: ‘hidden’ to prevent visible jumping
  6. Adjusted the card width calculation to account for margins
  7. Used two sets of cards (original and duplicate) for a seamless transition
  8. Added unique keys for both sets of cards to prevent React warnings

Make sure you add your image/icon back as I did not have the file, I removed the Icon/Image code and CSS for debugging.

import React, { useEffect, useRef } from 'react';
import { Animated, StyleSheet, Text, View, Dimensions } from 'react-native';

const cardData = [
  { id: 0, title: "Feeling Happy" },
  { id: 1, title: "Feeling Calm" },
  { id: 2, title: "Feeling Angry" },
  { id: 3, title: "Feeling Sad" },
];

const App = () => {
  const translateX = useRef(new Animated.Value(0)).current;
  const { width } = Dimensions.get('window');

  const Cards = ({ item }) => {
    return (
      <View style={styles.cards_con}>
        <Text style={styles.card_title}>{item.title}</Text>
      </View>
    );
  };

  useEffect(() => {
    const cardWidth = 220; // Width of card + horizontal margin
    const contentWidth = cardWidth * cardData.length;

    const startAnimation = () => {
      translateX.setValue(0); // Reset to start position
      
      Animated.sequence([
        Animated.timing(translateX, {
          toValue: -contentWidth,
          duration: 17000,
          useNativeDriver: true,
        }),
        // Reset the position instantly
        Animated.timing(translateX, {
          toValue: 0,
          duration: 0,
          useNativeDriver: true,
        })
      ]).start(() => {
        // Restart the animation when complete
        startAnimation();
      });
    };

    startAnimation();

    return () => {
      // Cleanup animation when component unmounts
      translateX.stopAnimation();
    };
  }, []);

  return (
    <View style={styles.container}>
      <View style={styles.clipContainer}>
        <Animated.View
          style={{
            flexDirection: 'row',
            transform: [{ translateX }],
          }}
        >
          {/* Original set of cards */}
          {cardData.map((item, index) => (
            <Cards key={`original-${index}`} item={item} />
          ))}
          {/* Duplicate set for seamless transition */}
          {cardData.map((item, index) => (
            <Cards key={`duplicate-${index}`} item={item} />
          ))}
        </Animated.View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#000",
  },
  clipContainer: {
    overflow: 'hidden',
    width: '100%',
  },
  cards_con: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "#323232",
    height: 50,
    borderRadius: 10,
    marginHorizontal: 10,
    padding: 10,
    width: 200,
  },
  card_title: {
    color: "#FFFFFF",
    fontSize: 16,
  },
});

export default App;
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading