-
Notifications
You must be signed in to change notification settings - Fork 25.1k
Description
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
- Create an
Animated.timinganimation - Set
useNativeDriverto true within the timing's options - Place this within one or more of
Animated.parallel,Animated.stagger,Animated.sequence - 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'
}
});