Search code examples
react-native

How to display the frames of several pictures as an animation on loop


I have several frames of an animation. I want to display the animation on a loop. I've read: https://reactnative.dev/docs/animations https://reactnative.dev/docs/animated https://blog.bitsrc.io/making-animations-in-react-native-the-simplified-guide-6580f961f6e8 And I have tried implementing: https://medium.com/react-native-training/react-native-animations-using-the-animated-api-ebe8e0669fae But none of them cover multiple frames of animation and how to loop through them using simple code. I'm sure what I need to do is v simple but these tutorials are over-whelming.

Here's some code I'm using: Just before the render

Images: [
        { id: 1, src: './assets//frame1.png', title: 'foo', description: 'bar' },
        { id: 2, src: './assets//frame2.png', title: 'foo', description: 'bar' },
        { id: 3, src: './assets//frame3.png', title: 'foo', description: 'bar' },
        { id: 4, src: './assets//frame4.png', title: 'foo', description: 'bar' },
        { id: 5, src: './assets//frame32.png', title: 'foo', description: 'bar' },

      ]

render() {
const items = this.state.Images.map((item, key) =>
    <Image key={item.id}>{item.name}</Image>

...

<View>
  {items}
</View>

That doesn't work - objects are not valid as a react child...

How would I simply display the first image of that array in the first place but then make it loop though each image (creating an animation).

Can anyone provide a simple block of code that demonstrates how to cycle/loop through several .png files in an assets folder as an animation on screen?

T


Solution

  • All you needed Interpolation through Opacity.

    • Just modify the data array like your Image array and display the images inside the Animating View.

    Iterate through your Image array and set the opacity Values.

        const data = ['red', 'green', 'blue', 'violet', 'pink', 'red'];
        this.animations = new Animated.Value(0);
        this.opacity = [];
        data.map((item, index) => {
          this.opacity.push(
            this.animations.interpolate({
              inputRange: [index - 1, index, index + 1],
              outputRange: [0, 1, 0],
            }),
          );
        });
    
    • Now this.opacity array will contain the corresponding opacity values for each item.

    Now start the loop. (here I am using 2 sec to animate from one image to other )

        Animated.loop(
          Animated.timing(this.animations, {
            toValue: length - 1,
            duration: 2000 * length,
            easing: Easing.linear,
            useNativeDriver: true,
          }),
        ).start();
    

    Set opacity for each item inside the render

        const opacity = this.opacity[index];
    

    Full Code (example)

    import React, {Component} from 'react';
    import {View, StyleSheet, Animated, Easing} from 'react-native';
    
    const data = ['red', 'green', 'blue', 'violet', 'pink', 'red'];
    
    const length = data.length;
    
    export default class App extends Component {
      constructor() {
        super();
        this.animations = new Animated.Value(0);
        this.opacity = [];
        data.map((item, index) => {
          this.opacity.push(
            this.animations.interpolate({
              inputRange: [index - 1, index, index + 1],
              outputRange: [0, 1, 0],
            }),
          );
        });
      }
    
      componentDidMount() {
        Animated.loop(
          Animated.timing(this.animations, {
            toValue: length - 1,
            duration: 2000 * length,
            easing: Easing.linear,
            useNativeDriver: true,
          }),
        ).start();
      }
    
      render() {
        return (
          <View style={styles.container}>
            {data.map((item, index) => {
              const opacity = this.opacity[index];
              return (
                <Animated.View
                  style={[styles.item, {backgroundColor: item, opacity}]}
                />
              );
            })}
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
      },
      item: {
        height: 200,
        width: 200,
        position: 'absolute',
      },
    });
    

    I hope it will help you.