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 does not loop when native drivers are used #28517

Closed
delventhalz opened this issue Apr 3, 2020 · 10 comments
Closed

Animation does not loop when native drivers are used #28517

delventhalz opened this issue Apr 3, 2020 · 10 comments
Labels
API: Animated Needs: Attention Issues where the author has responded to feedback. Newer Patch Available Resolution: Locked This issue was locked by the bot.

Comments

@delventhalz
Copy link

delventhalz commented Apr 3, 2020

Description

Building a fairly complex "pulsing" animation, which includes nested calls to Animated.loop, Animated.sequence, Animated.stagger, Animated.parallel, and finally Animated.timing. This animation works as expected with useNativeDriver set to false. Unfortunately, when set to true, the animation only plays once and never loops.

I have attempted to find a workaround, and while I can get a simple animation with just a loop and timing to repeat with native drivers, once I introduce parallel, stagger, or sequence it stops repeating. I have not confirmed 100% that every combination of those three functions break looping in native, but suffice to say I have been unable to find a workaround.

I have also tried looping with a recursive call passed to start instead of Animated.loop. This doesn't make any difference, and also does not repeat when useNativeDriver is set to true.

React Native version:

System:
    OS: macOS Mojave 10.14.6
    CPU: (4) x64 Intel(R) Core(TM) i5-8210Y CPU @ 1.60GHz
    Memory: 2.54 GB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.13.0 - /usr/local/bin/node
    Yarn: 1.17.3 - /usr/local/bin/yarn
    npm: 6.12.0 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.8.4 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.2
      System Images: android-28 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.5977832
    Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild
  Languages:
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^16.13.1 => 16.13.1 
    react-native: ^0.62.1 => 0.62.1 
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  1. Create an Animated.timing animation
  2. Set useNativeDriver to true within the timing's options
  3. Place this within one or more of Animated.parallel, Animated.stagger, Animated.sequence
  4. Place these calls within Animated.loop

Expected Results

Animation should repeat

Code Example

import { times } from 'lodash';
import React, { useState, useEffect } from 'react';
import { Animated, Dimensions, Easing, StyleSheet, View } from 'react-native';

const Pulse = ({ opacity, size, startSize }) => {
  const scale = Animated.divide(size, startSize);
  const position = startSize / -2;

  return (
    <Animated.View
      style={[
        styles.pulse,
        {
          borderRadius: size,
          height: startSize,
          left: position,
          opacity,
          scaleX: scale,
          scaleY: scale,
          top: position,
          width: startSize
        }
      ]}
    />
  );
};

const arrayBuilder = size => iteratee => times(size, iteratee);

const expandAnimator = (duration, endSize, endOpacity) => (size, opacity) => {
  const options = {
    duration,
    useNativeDriver: true
  };

  return Animated.parallel([
    Animated.timing(size, { ...options, toValue: endSize }),
    Animated.timing(opacity, { ...options, toValue: endOpacity })
  ]);
};

export const Pulsar = ({
  count = 4,
  startSize = 86,
  endSize = Dimensions.get('window').width,
  startOpacity = 1,
  endOpacity = 0,
  duration = 2750,
  interval = 600,
  delay = 2400
}) => {
  const countOf = arrayBuilder(count);
  const [sizes] = useState(countOf(() => new Animated.Value(startSize)));
  const [opacities] = useState(countOf(() => new Animated.Value(startOpacity)));

  useEffect(() => {
    const animateExpand = expandAnimator(duration, endSize, endOpacity);
    const expansions = countOf(i => animateExpand(sizes[i], opacities[i]));

    Animated.loop(
      Animated.sequence([
        Animated.stagger(interval, expansions),
        Animated.delay(delay)
      ])
    ).start();
  }, []);

  return (
    <View>
      {countOf(i => (
        <Pulse
          key={i}
          opacity={opacities[i]}
          size={sizes[i]}
          startSize={startSize}
        />
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  pulse: {
    backgroundColor: '#F00',
    position: 'absolute'
  }
});
@github-actions
Copy link

github-actions bot commented Apr 3, 2020

⚠️ Using Old Version
ℹ️ It looks like you are using an older version of React Native. Please upgrade to the latest version, and verify if the issue persists. If it does not, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the current release.

@delventhalz
Copy link
Author

Confirmed with the following (latest) versions. Updating the original commment:

System:
    OS: macOS Mojave 10.14.6
    CPU: (4) x64 Intel(R) Core(TM) i5-8210Y CPU @ 1.60GHz
    Memory: 2.54 GB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.13.0 - /usr/local/bin/node
    Yarn: 1.17.3 - /usr/local/bin/yarn
    npm: 6.12.0 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.8.4 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.2
      System Images: android-28 | Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.5977832
    Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild
  Languages:
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: ^16.13.1 => 16.13.1 
    react-native: ^0.62.1 => 0.62.1 
  npmGlobalPackages:
    *react-native*: Not Found

@github-actions github-actions bot added Needs: Attention Issues where the author has responded to feedback. and removed Needs: Author Feedback labels Apr 3, 2020
@Tristan1075
Copy link

Same here with RN 0.62.1

@stale
Copy link

stale bot commented Jul 20, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Jul 20, 2020
@delventhalz
Copy link
Author

This is still an issue. And it has been confirmed on the latest version. The labels should be updated.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jul 20, 2020
@RnbWd
Copy link

RnbWd commented Jul 22, 2020

On my first attempt to build a similar animation, I ran into the same issue. If I wrap Animated.loop around Animated.timing, it seems to work, but my animation is wrong now. Wrapping Animated.loop around Animated.stagger doesn't work with nativeDriver

@Windovvsill
Copy link

I just stumbled onto this as well. Loops correctly when not using native drivers.
Any chance on getting the above PR merged?

@sooakim
Copy link

sooakim commented Jan 16, 2021

Animated.sequence([
  Animated.timing({
    ...something,
    useNativeDriver: true
  }),
  Animated.timing({
    duration: 0,
    ..reset position,
    useNativeDriver: true
  }),
  ...loop iterations count
])

I just solved by NOT using Animated.loop. But It’s not a perfect solution...

@castrolem
Copy link

I'm encountering a similar issue when adding Animated.sequence, in my case the loop does not break and displays correctly, but there seems to be a memory leak, since even when I call animation.stop() none of my functions wrapped on InteractionsManager.runAfterInteractions(...) run.

Here's my example code for the animation

const animation = useRef(
    Animated.loop(
      Animated.sequence([
        Animated.timing(value, {
          toValue: 1,
          duration: 2500,
          useNativeDriver: false,
        }),
        Animated.delay(4000),
        Animated.timing(value, {
          toValue: 0,
          duration: 1,
          useNativeDriver: false,
        }),
      ])
    )
  ).current;

@SampsonCrowley
Copy link

On my first attempt to build a similar animation, I ran into the same issue. If I wrap Animated.loop around Animated.timing, it seems to work, but my animation is wrong now. Wrapping Animated.loop around Animated.stagger doesn't work with nativeDriver

wrapping loop directly around timing fixes it for me on android, but then causes the same problem for web where it was working previously; looks like it's time for a Platform hack

@facebook facebook locked as resolved and limited conversation to collaborators May 13, 2022
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label May 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
API: Animated Needs: Attention Issues where the author has responded to feedback. Newer Patch Available Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants