我的组件中有一个简单的循环动画,如下所示:
runAnimation() {
console.log('run animation');
this.state.angle.setValue(0);
Animated.timing(this.state.angle, {
toValue: 360,
duration: 8000,
easing: Easing.linear
}).start(() => this.runAnimation());
}
...
<Animated.Image
style={[
styles.rotate,
{ transform: [
{ rotate: this.state.angle.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg']
})},
]}
]}
source={require('./spinning_ball.png')}
/>
如何停止此动画?例如,导航到另一个屏幕或用户点击按钮后。
我尝试使用 this.state.angle.stopAnimation(),但发现运行动画仍在控制台中打印。我应该调用一个不同的stop方法来阻止执行启动回调吗?
答案 0 :(得分:14)
基于我在NguyênHoàng的回答中的评论。如果您调用this.state.angle.stopAnimation()
:
runAnimation() {
this.state.angle.setValue(0);
Animated.timing(this.state.angle, {
toValue: 360,
duration: 8000,
easing: Easing.linear
}).start((o) => {
if(o.finished) {
this.runAnimation();
}
});
}
答案 1 :(得分:3)
您可以创建变量,
,以便只在stopAnimation
然后回调stopAnimation === false
函数时停止动画。例如:
runAnimation
所以你只需要创建一个调用函数this.state = { stopAnimation: false }
runAnimation() {
this.state.spinValue.setValue(0);
Animated.timing(
this.state.spinValue,
{
toValue: 1,
duration: 3000,
easing: Easing.linear
}
).start( () => {
if(this.state.stopAnimation === false) {
this.runAnimation();
}
});
}
来停止动画的按钮。
答案 2 :(得分:3)
我喜欢将我的动画封装在钩子中,与类组件相比,它使图案更简洁,更易用,更可重用。这是我在打字稿中使用轻松的开始/停止控制来制作循环动画的方法:
export const useBounceRotateAnimation = (running: boolean = true, rate: number = 300) => {
//Example of making an infinite looping animation and controlling it with a boolean
//Note that this assumes the "rate" is constant -- if you wanted to change the rate value after creation the implementation would have to change a bit
//Only create the animated value once
const val = useRef(new Animated.Value(0))
//Store a reference to the animation since we're starting-stopping an infinite loop instead of starting new animations and we aren't changing any animation values after creation. We only want to create the animation object once.
const anim = useRef(
Animated.loop(
Animated.timing(val.current, {
toValue: 1,
duration: rate,
easing: Easing.linear,
useNativeDriver: true,
isInteraction: false,
})
)
).current
//Interpolate the value(s) to whatever is appropriate for your case
const interpolatedY = val.current.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0, 6, 0],
})
const interpolatedRotate = val.current.interpolate({
inputRange: [0, 0.25, 0.5, 1],
outputRange: ["0deg", "-3deg", "3deg", "0deg"],
})
//Start and stop the animation based on the value of the boolean prop
useEffect(() => {
if (running) {
anim.start()
} else {
//When stopping reset the value to 0 so animated item doesn't stop in a random position
anim.stop()
val.current.setValue(0)
}
//Return a function from useEffect to stop the animation on unmount
return () => anim.stop()
//This useEffect should rerun if "running" or "anim" changes (but anim won't change since its a ref we never modify)
}, [running, anim])
//Return the animated values. Use "as const" const assertion to narrow the output type to exactly the two values being returned.
return [interpolatedY, interpolatedRotate] as const
}
我使用这个实际的钩子实现在游戏中制作角色图像“行走”。现在在我的组件中,它非常易于使用:
const MyComponent = () => {
const [isRunning, setIsRunning] = useState(true)
const [translation, rotation] = useBounceRotateAnimation(isRunning)
return (
<Animated.View
style={{
transform: [{ translateY: translation}, { rotate: rotation}],
}}
>
....rest of your component here, just setIsRunning(false) to stop animation whenever you need
</Animated.View>
)
}
如您所见,此模式非常干净且可重用。动画组件不需要了解有关动画的任何信息,它仅消耗动画值并告诉动画何时运行。
答案 3 :(得分:0)
您可以使用以下方法停止循环:
componentWillUnmount() {
Animated.timing(this.state.angle).stop();
}
答案 4 :(得分:0)
通过调用setValue()
方法并分配一个值来停止循环动画的最简单方法。喜欢:
const [opacity, setOpacity] = useState(new Animated.value(0));
// declare your looping animated function
// Any time to stop the looping animated function just call setValue()
// on your stop animation event or function using opcacity reference. like
opacity.setValue(0)
有关更多详细信息,https://reactnative.dev/docs/animatedvaluexy#setvalue