如何实现带曲线启动与停止效果的重复AnimationController?
解决可重复播放且启停带曲线动画的AnimationController问题
嘿,我来帮你搞定这个动画需求!要让AnimationController启动时带曲线动画进入重复循环,停止时也用曲线平滑过渡,我们需要调整动画的构建方式和启停逻辑,下面是具体的解决方案:
核心思路
- 启动阶段:先通过曲线动画从初始值过渡到循环终点,完成后自动触发无限重复播放
- 停止阶段:用
animateBack结合曲线过渡到初始状态,动画结束后自动重置控制器状态 - 状态同步:通过动画状态监听来管理
_animating变量,避免手动设置导致的状态冲突
完整代码实现
import 'dart:math'; import 'package:flutter/material.dart'; class RotationAnimationDemo extends StatefulWidget { const RotationAnimationDemo({super.key}); @override State<RotationAnimationDemo> createState() => _RotationAnimationDemoState(); } class _RotationAnimationDemoState extends State<RotationAnimationDemo> with SingleTickerProviderStateMixin { bool _animating = false; late AnimationController _rotationAnimationController; late Animation<double> _animation; @override void initState() { super.initState(); _rotationAnimationController = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this, ); // 整合曲线到动画中:启动阶段使用指定曲线,循环阶段切换为匀速 _animation = Tween<double>(begin: 0, end: 4 * pi).animate( CurvedAnimation( parent: _rotationAnimationController, curve: Curves.easeIn, // 启动时的入场曲线,可按需替换 ), )..addListener(() { setState(() {}); })..addStatusListener((status) { // 第一次动画完成后,若仍处于激活状态则开启无限重复 if (status == AnimationStatus.completed && _animating) { _rotationAnimationController.repeat( reverse: false, // 若需要来回旋转可设为true ); } // 反向动画完成(回到初始状态)后,重置激活状态 if (status == AnimationStatus.dismissed) { setState(() { _animating = false; }); } }); } @override void dispose() { _rotationAnimationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { const startStopDuration = Duration(seconds: 3); if (_animating) { // 停止时:用曲线动画平滑回到初始角度 _rotationAnimationController.animateBack( 0, duration: startStopDuration, curve: Curves.easeOut, ); } else { setState(() { _animating = true; }); // 启动时:先执行一次带曲线的入场动画,之后自动进入循环 _rotationAnimationController.forward(); } }, child: Container( width: 120, height: 120, color: Colors.deepPurple, alignment: Alignment.center, child: Transform.rotate( angle: _animation.value, child: const Text( "旋转图标", style: TextStyle(color: Colors.white, fontSize: 16), ), ), ), ); } }
关键细节解释
- 动画构建:用
CurvedAnimation将曲线与控制器绑定,确保第一次启动动画应用指定曲线 - 启动逻辑:点击启动时调用
forward(),动画完成后通过状态监听触发repeat(),无缝进入循环 - 停止逻辑:点击停止时调用
animateBack(0),结合Curves.easeOut实现平滑减速停止,动画回到初始状态后自动更新_animating - 状态安全:通过
AnimationStatus监听同步状态,避免手动设置_animating导致的动画冲突
如果需要让每一轮循环都带曲线,只需把repeat()替换为带CurvedAnimation的动画即可,但通常启动阶段用曲线、循环阶段匀速的体验会更自然。
内容的提问来源于stack exchange,提问作者Tobias H.
相关产品推荐
相关产品推荐

