React中如何在 onPress 触发时让动画完成当前周期后停止
解决方案:让动画完成当前阶段后再停止
这个问题我之前也碰到过,直接用Animated.loop的stop()确实会粗暴中断动画,想要让动画完成当前关键阶段再停止,我们可以换个思路——手动控制动画循环,而不是依赖Animated.loop的内置循环逻辑。
核心思路
- 用
useRef保存一个停止标记(shouldStop),因为我们需要即时修改和读取状态,且不需要触发组件重渲染。 - 将原来的
Animated.loop拆分为递归调用的动画序列,在每个动画步骤完成后检查停止标记,决定是否继续执行后续动画。 - 点击停止按钮时,仅标记停止状态,让当前动画自然完成后自动终止。
完整代码示例
import React, { useRef } from 'react'; import { Animated, Button, Text, View } from 'react-native'; const Animated_2 = (props) => { // 初始化透明度动画值,默认完全不透明 const animation = useRef(new Animated.Value(1)).current; // 停止标记,用useRef避免组件重渲染 const shouldStop = useRef(false); const startAnimation = () => { // 启动前重置停止标记 shouldStop.current = false; const runCycle = () => { // 如果已经标记停止,直接退出 if (shouldStop.current) return; // 第一步:透明度从1降到0 Animated.timing(animation, { toValue: 0, duration: props.duration, useNativeDriver: false, }).start(({ finished }) => { // 如果动画未正常完成(比如意外中断),直接退出 if (!finished) return; // 检查是否需要停止:如果是,就终止,不再执行后续动画 if (shouldStop.current) { return; } // 第二步:透明度从0回到1,完成后开启下一轮循环 Animated.timing(animation, { toValue: 1, duration: props.duration, useNativeDriver: false, }).start(({ finished }) => { if (finished && !shouldStop.current) { runCycle(); } }); }); }; // 启动第一轮动画 runCycle(); }; const stop = () => { // 仅标记停止状态,让当前动画自然完成后终止 shouldStop.current = true; }; return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', gap: 16 }}> <Animated.Text style={{ opacity: animation, fontSize: 24 }}> 闪烁的文本 </Animated.Text> <Button title="启动动画" onPress={startAnimation} /> <Button title="停止动画" onPress={stop} /> </View> ); }; export default Animated_2;
关键细节说明
- 停止逻辑:当你点击停止按钮时,
shouldStop.current被设为true,当前正在执行的动画会继续完成(比如从40%透明度降到0%),完成后检查到停止标记,就不会再执行后续的动画步骤或下一轮循环。 - 手动循环:通过递归调用
runCycle来实现动画的重复,相比Animated.loop,这种方式让我们完全掌控每个动画阶段的执行逻辑,灵活实现“完成当前阶段再停止”的需求。 - useRef的作用:用
useRef保存shouldStop和animation,可以避免因状态更新触发的组件重渲染,同时保证状态读取和修改的即时性。
内容的提问来源于stack exchange,提问作者Jerry Seigle
相关产品推荐
相关产品推荐

