Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation is stopped after has entered background state #412

Closed
houmark opened this issue Dec 2, 2018 · 17 comments
Closed

Animation is stopped after has entered background state #412

houmark opened this issue Dec 2, 2018 · 17 comments
Assignees

Comments

@houmark
Copy link

houmark commented Dec 2, 2018

Description

Animation is stopped after app has entered background state. This seems to mainly be a problem on iOS, on Android I was not able to reproduce it easily in the emulator, but it may also be an issue in Android.

Steps to Reproduce

  1. Create a looping lottie animation
  2. Sleep/close the app
  3. Re-open the app

Expected behavior: [What you expected to happen]

Animation is still running or starts again.

Actual behavior: [What actually happened]

Animation is stopped.

Versions

2.5.10

I'm working around this by setting a ref on the <LottieView> then using an event listener I'm playing the animation again if and when the animation is looping and mounted in the current view/screen.

Is this expected behavior? It becomes a bit tedious to keep track of n animations inside the component in order to play() them again when the app becomes active, and I would expect that a looping animation would continue after the app has been in the background/sleeping.

@lorenc-tomasz
Copy link
Contributor

The same issue.

@emilioicai
Copy link
Member

it's not expected behavior but it's a side effect of trying to make the library as performant as possible. We definitely need to keep track within the library if the animation is running when the component is unmounted and reset it when the component is mounted again.

@emilioicai emilioicai self-assigned this Dec 3, 2018
@lorenc-tomasz
Copy link
Contributor

Any idea how to fix this issue?

@emilioicai
Copy link
Member

@lorenc-tomasz we will fix this on the library. For the time being you can use @houmark's workaround:

I'm working around this by setting a ref on the then using an event listener I'm playing the animation again if and when the animation is looping and mounted in the current view/screen.

@houmark
Copy link
Author

houmark commented Dec 5, 2018

Here's the workaround:

export default class YourComponentName extends Component {

  state = {
    appState: null,
  }

  componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange);
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }

  _handleAppStateChange = nextAppState => {
    const { appState } = this.state;
    if (appState && appState.match(/inactive|background/) && nextAppState === 'active') {
      if (this._animation) {
        this._animation.play();
      }
    }
    this.setState({ appState: nextAppState });
  };

  _setAnimation = ref => {
    this._animation = ref;
  };

  render() {
    return (
      <LottieView
        source={require('../assets/lottie/animation.json')}
        autoPlay
        loop={true}
        ref={this._setAnimation}
      />
    );
  }

};

@lorenc-tomasz
Copy link
Contributor

Thanks :)

@slorber
Copy link

slorber commented Jan 2, 2019

Thanks @houmark that seems to work fine for me too.

Here's a TS version:

import React, { Component } from 'react'
import { AppState, AppStateStatus } from 'react-native'
import Lottie from 'lottie-react-native'

type extractComponentPropsType<Type> = Type extends Component<infer X>
  ? X
  : null

// See https://github.com/react-native-community/lottie-react-native/issues/426
type LottieProps = extractComponentPropsType<Lottie>

interface State {
  appState: AppStateStatus
}

// Because Lottie has a bug that stops animation when in background (ios)
// See https://github.com/react-native-community/lottie-react-native/issues/412
export class LottieAnimation extends Component<LottieProps, State> {
  state: State = {
    appState: AppState.currentState
  }

  ref = React.createRef<Lottie>()

  componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange)
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange)
  }

  _handleAppStateChange = (nextAppState: AppStateStatus) => {
    const { appState } = this.state
    this.setState({ appState: nextAppState })
    if (appState.match(/inactive|background/) && nextAppState === 'active') {
      if (this.ref.current) {
        this.ref.current!.play()
      }
    }
    this.setState({ appState: nextAppState })
  }

  render() {
    return <Lottie ref={this.ref} autoPlay={true} {...this.props} />
  }
}

@slorber
Copy link

slorber commented Jan 2, 2019

Just want to point out that this bug has been reported when working on Expo in dev/prod. Our build APK on testflight does not seem to be affected.

@jogasinghbajwa
Copy link

jogasinghbajwa commented Feb 12, 2019

Hi, I'm also facing the same issue, I tried @houmark's workaround, But when my application becomes active after goes to background state, I got this error.
simulator screen shot - iphone x - 2019-02-12 at 11 11 40
Please help me to resolve this issue.
My js file code as follows:

import { AppState, AppStateStatus } from 'react-native'
this.state = {
appState: null,
}

componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}

componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
}

 _handleAppStateChange = nextAppState => {
        const { appState } = this.state;
        if (appState === 'inactive' || appState === 'background' && nextAppState === 'active') {
          if (this._animation) {
           this._animation.play();
          }
        }
        this.setState({ appState: nextAppState });
      };
    
      _setAnimation = ref => {
        this._animation = ref;
      };

<Lottie
                                    autoPlay={true}
                                    duration={8000}
                                    loop={true}
                                    style={[styles.setting, {
                                        transform: [{
                                            scale: this.state.AnimatePressSetting
                                        }]
                                    }]}
                                    source={require('../animations/gear.json')}
                                    ref={this._setAnimation}
                                />

If i use this code

_handleAppStateChange = nextAppState => {
       const { appState } = this.state;
       if (appState.match(/inactive|background/) && nextAppState === 'active') {
         if (this._animation) {
           this._animation.play();
         }
       }
       this.setState({ appState: nextAppState });
     };

I'm facing this issue.
simulator screen shot - iphone x - 2019-02-12 at 11 20 07

@kthaas
Copy link

kthaas commented Mar 15, 2019

Thanks @houmark for the fix! Quick comment: you missed a check for appState being null in the initial case. This line:
if (appState.match(/inactive|background/) && nextAppState === 'active') {
Should be:
if (appState !== null && appState.match(/inactive|background/) && nextAppState === 'active') {

@houmark
Copy link
Author

houmark commented Mar 16, 2019

@kthaas Yeah, so I did some copy pasting from my original code that has more logic than this basic example, but thanks for the update, I will update the example.

@houmark
Copy link
Author

houmark commented Mar 16, 2019

What one can do on top of this example is also checking if the animations are loop true and only restart the animation if it is, so you don't start animations after sleep that only run once. That's what I have in my code on some animations. It's basically case by case situations...

To do that check:

if (this._setAnimation && this._setAnimation.props.loop) {
  this._setAnimation.play();
}

@tuanduongdn1504
Copy link

tuanduongdn1504 commented Jun 8, 2019

Thanks all, I have just want to mark final solution for this problem in IOS platform

import React, { Component } from 'react'
import { AppState, AppStateStatus } from 'react-native'
import Lottie from 'lottie-react-native'

export default class YourComponentName extends Component {

  state = {
    appState: null,
  }

  componentDidMount() {
    AppState.addEventListener('change', this._handleAppStateChange);
  }

  componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }

  onHandleAppStateChange = nextAppState => {
    const { appState } = this.state;

    // a check for appState being null in the initial case
    if (appState !== null && appState && appState.match(/inactive|background/) && nextAppState === 'active') {
      if (this._animation) {
        this._animation.play();
      }
    }
    this.setState({ appState: nextAppState });
  };

  onSetAnimation = ref => {
    this._animation = ref;
  };

  render() {
    return (
      <LottieView
        source={require('../assets/lottie/animation.json')}
        autoPlay
        loop={true}
        ref={this._setAnimation}
      />
    );
  }

};

@buluoray
Copy link

buluoray commented Aug 8, 2019

In ios version, there is a yourLottieAnimationView.backgroundBehavior = .pauseAndRestore works perfectly for me

@slorber
Copy link

slorber commented Aug 8, 2019

you mean on the native SDK? because I don't find this param documented in this repo

@buluoray
Copy link

buluoray commented Aug 8, 2019

I believe so, just try typing it in xcode.

@etouyang
Copy link

it seems that latest version not solve the bug, why closed it...

matinzd added a commit to matinzd/lottie-react-native that referenced this issue Oct 26, 2019
Fix AnimationUIblock on scroll or when mounting and unmounting components in ios
matinzd added a commit to matinzd/lottie-react-native that referenced this issue Oct 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants