How to make a Slider that updates based on Lottie animation progress (React-Native)

Viewed 1957

I'm trying to get a Slider to update its position based upon the Progress value of a Lottie animation. The Slider can control the Lottie's Progress, but it doesn't update its position if I press the "Play Lottie" Button. How can I have components access the Lottie's Progress value and update based on what the Progress value is? I want this value to be public or accessible from other components. It seems like the Progress value isn't accessible by outside components. I tried "addListener," but it doesn't do anything.

I'm new to react-native and coding in general. I've looked around StackOverflow for many days and couldn't find anything.

export default class HomeScreen extends React.Component {
    constructor(props) {
        super(props);
        this.playLottie.bind(this);
        this.playLottie.bind(this);
        this.pauseLottie.bind(this);
        this.state = {
            progress: new Animated.Value(0),
            pausedProgress: 0
        };
        this.state.progress.addListener(({ value }) => this._value = value); // I tried to use a Listener so that components can Listen to the Progress of the lottie animation...
    }

    playLottie = () => {
        Animated.timing(this.state.progress, {
            toValue: 1,
            easing: Easing.linear,

        }).start;
    }

    //Shows real-time value of the Slider. Console output works too, updates when I use slider in realtime.
    realProgress = (value) => {
        console.log("realProgress", value);
        this.setState({ pausedProgress: value });
    };

    //Used by Slider, sets Progress of Lottie
    setProgress = (value) => {
        this.state.progress.setValue(value);
        console.log("setProgress", value)
    };

    render() {
        return (

            <View style={styles.container}>
                <ScrollView style={styles.container} contentContainerStyle={styles.contentContainer}>
                //The Lottie Animation:
                <LottieView
                        ref={animation => { this.animation = animation; }}
                        source={require('../assets/lottie-animations/animation.json')}
                        style={{ height: 400, width: '100%' }}
                        loop={false}
                        progress={this.state.progress}
                />

                <Button
                    onPress={this.playLottie}
                    title="Play Lottie"
                />
                <Button
                    onPress={this.pauseLottie}
                    title="Pause Lottie"
                    />

                //The slider that controls the progress of the Lottie Animation:
                <Slider
                    style={{ width: '100%', height: 40 }}
                    minimumValue={0}
                    maximumValue={1}
                    onValueChange={(value) => this.setProgress(value)}
                />

                //Tried using Text to display the real-time value of the Lottie animation progress. Doesn't display any numbers.
                <Text>{'Slider Position: '}{Slider.onValueChange}</Text>

                </ScrollView>
            </View>

        );
    }
}

Relevant dependencies:

"dependencies": {
    "expo": "~36.0.0",
    "lottie-react-native": "^3.3.2",
    "react": "~16.9.0",
    "react-lottie": "^1.2.3",
    "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
  },

Expo Version: 3.13.8
Windows 10

1 Answers

Use imperative API it is much simpler.

Constructor

  constructor(props) {
    super(props);

    this.state = {
      progress: 0,
    }
  }

Use the componentDidMount for testing. play(startFrame, EndFrame). You will need to find out the animations end frame number to use with the slider. Keep changing the endframe until it plays until the end --that's your number.

  componentDidMount() {
    // Or set a specific startFrame and endFrame with:
    // this.animation.play(0, 100);
  }

An arrow function that returns the value and changes the state of progress. You can set the animation frame rate to start and stop on the same frame.

  animateIt = (value) => {
    //this.animation.reset();
    this.setState({progress: value})
    this.animation.play(value, value);
  }

Your lottie component

  <LottieView
    ref={animation => {
      this.animation = animation;
    }}
    style={{ height: 400, width: '100%' }}
    source={require('../assets/lottie-animations/animation.json')}
  />

Your slider set the maximum value to equal the last frame of the animation. In my case it was 40. Also the slider calls the arrow function and returns the value.

  <Slider
      style={{ width: '100%', height: 40 }}
      minimumValue={0}
      maximumValue={40}
      onValueChange={(value) => this.animateIt(value)}
  />
Related