Reputation: 1124
React-native introduce new Animated
API, I want to make a loop animation such as a bubble scale up then scale down and repeat that progress.
However I can not figure it out. I've tried write some code like below
class TestProject extends React.Component {
constructor(): void {
super();
this.state = {
bounceValue: new Animated.Value(0),
v: 1,
};
}
componentDidMount() {
this.state.bounceValue.setValue(1.5);
let animation = Animated.timing(this.state.bounceValue, {
toValue: this.state.v,
});
setInterval(() => {
animation.stop();
if (this.state.flag) {
this.state.v = 0.5;
this.state.bounceValue.setValue(0.5);
}
else {
this.state.v = 1.5;
this.state.bounceValue.setValue(1.5);
}
animation.start();
}, 5000);
}
render(): ReactElement {
return (
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={{uri: 'http://image142-c.poco.cn/best_pocoers/20130517/91062013051716553599334223.jpg'}}
/>
<Animated.Text
style={[
styles.test,
{transform: [
{scale: this.state.bounceValue},
],}
]
}>
haha
</Animated.Text>
</View>
);
}
}
but not works very well.
Any suggestion will be appreciate.
Upvotes: 51
Views: 45987
Reputation: 2288
Here's another example for an infinite animation using hooks and iterations
set to "infinity". Avoids the use of the recursion in previous answers which sometimes led to funky behaviour during e2e testing for us.
const rotation = React.useRef(new Animated.Value(0)).current;
function runAnimation() {
return Animated.loop(
Animated.timing(rotation, {
toValue: 1,
duration: 1200,
easing: Easing.linear,
useNativeDriver: true,
}),
{resetBeforeIteration: true, iterations: Number.MAX_SAFE_INTEGER},
);
}
React.useEffect(() => {
const animation = runAnimation();
return () => animation.stop();
}, []);
Upvotes: 1
Reputation: 13184
Not sure if it's hacky, but I use this:
Animated.spring(this.state.rotation, {
toValue: 5,
stiffness: 220, // the higher value, the faster the animation
damping: 0.000001, // never stop wiggle wiggle wiggle
}).start();
It's creating spring animation that will never (technically, for a very very very long time) stop waving.
For most of my cases it was enough. Also it has great performance as it does not require any JS tread action ever during animation.
If eventually you'd like to stop it gracefully:
Animated.spring(this.state.rotation, {
toValue: 0,
stiffness: 220, // the higher value, the faster the animation
damping: 10, // never stop wiggle wiggle wiggle
}).start();
And it'll nicely 'slow down' until it stops.
Upvotes: 0
Reputation: 1263
Try something like this:
componentDidMount() {
this.bootAnimation();
}
bootAnimation() {
this.animation = Animated.loop(
Animated.timing(this.state.progress, {
toValue: 1,
duration: 5000
})
).start();
}
Upvotes: 6
Reputation: 4566
There's now loop animation available:
Animated.loop(
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]),
{
iterations: 4
}
).start()
Upvotes: 146
Reputation: 1034
improved version of @bcomerford answer
//this.state.animatedStartValue = 0;
function cycleAnimation() {
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]).start(event => {
if (event.finished) {
cycleAnimation();
}
});
}
Upvotes: 19
Reputation: 34
You can set another animation then call the animation again:
An example I did to fade text in and out:
textAnimate: function() {
Animated.timing(
this.state.textOpacity,
{
toValue: 0.3,
duration: 500,
}
).start(() => {
Animated.timing(
this.state.textOpacity,
{
toValue: 1,
duration: 500,
}
).start(() => {
this.textAnimate();
});
});
},
componentDidMount: function() {
this.state.textOpacity.setValue(1)
this.textAnimate();
},
Upvotes: 0
Reputation: 433
I use the sequence method to pass an array of animations to cycle and then repeat the function.
//this.state.animatedStartValue = 0;
function cycleAnimation() {
Animated.sequence([
Animated.timing(this.state.animatedStartValue, {
toValue: 1,
duration: 500,
delay: 1000
}),
Animated.timing(this.state.animatedStartValue, {
toValue: 0,
duration: 500
})
]).start(() => {
cycleAnimation();
});
}
If I'm toggling that animation on it's own it will fade in/out, however I layer it on top of a base to mimic an active state or hotspot-style button
<TouchableOpacity>
<Animated.Image
source={activeImageSource}
style={this.state.animatedStartValue}}
/>
<Image source={nonActiveImageSource}
/>
</TouchableOpacity>
React Native Sequence Documentation
Upvotes: 40
Reputation: 1490
It seems that 'looping' is not supported by the Animated
api for now.
I managed to do that by start the animation again when it finished.
startAnimation() {
Animated.timing(this._animatedValue, {
toValue: 100,
duration: 1000,
}).start(() => {
this.startAnimation();
});
}
Looking forward to a better solution...
Upvotes: 1