Flutter中实现起止值相同的动画方案咨询
解决Flutter中“先收缩再恢复”的起止值相同动画问题
你的问题核心出在动画执行顺序的控制逻辑上——你当前的代码里,_controller.forward()和_controller.reverse()几乎是同时触发的,因为Future.delayed并没有阻塞后续代码执行,导致动画刚要启动就被反向操作打断,自然看不到预期效果。下面给你几种靠谱的实现方式:
方案一:利用forward()的Future回调
AnimationController.forward()会返回一个Future,当动画执行完成时这个Future会完成,我们可以用then()链式调用reverse(),确保两个动画步骤顺序执行:
FlatButton( onPressed: () { setState(() { isSignUp = !isSignUp; }); // 先执行forward动画,完成后自动触发reverse _controller.forward().then((_) => _controller.reverse()); }, )
方案二:监听动画状态
通过给控制器添加状态监听器,当动画进入completed状态(即forward执行完毕)时,自动触发反向动画:
void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: Duration(milliseconds: 1000), ); _insetAnimation = Tween<EdgeInsetsGeometry>( begin: EdgeInsets.symmetric(horizontal: 0), end: EdgeInsets.symmetric(horizontal: 500), ).animate( CurvedAnimation( parent: _controller, curve: Curves.bounceIn, // 可以给反向动画单独设置曲线,比如回弹效果 reverseCurve: Curves.bounceOut, ), ); _insetAnimation.addListener(() => setState(() {})); // 添加状态监听器,控制动画流程 _controller.addStatusListener((status) { if (status == AnimationStatus.completed) { _controller.reverse(); } }); } // 按钮点击只需触发forward即可 FlatButton( onPressed: () { setState(() { isSignUp = !isSignUp; }); _controller.forward(); }, )
方案三:用TweenSequence实现单次完整循环动画
如果不想手动控制forward和reverse,可以直接用TweenSequence定义一个“初始值→目标值→初始值”的完整动画序列,只需一次forward()就能完成整个收缩再恢复的过程:
void initState() { super.initState(); _controller = AnimationController( vsync: this, // 总时长为两段动画的时间之和,这里各1秒,总2秒 duration: Duration(milliseconds: 2000), ); // 定义序列动画:先从0到500(占总时长50%),再从500回到0(占总时长50%) _insetAnimation = TweenSequence<EdgeInsetsGeometry>([ TweenSequenceItem( tween: Tween<EdgeInsetsGeometry>( begin: EdgeInsets.symmetric(horizontal: 0), end: EdgeInsets.symmetric(horizontal: 500), ), weight: 1.0, ), TweenSequenceItem( tween: Tween<EdgeInsetsGeometry>( begin: EdgeInsets.symmetric(horizontal: 500), end: EdgeInsets.symmetric(horizontal: 0), ), weight: 1.0, ), ]).animate( CurvedAnimation( parent: _controller, curve: Curves.easeInOut, ), ); _insetAnimation.addListener(() => setState(() {})); } // 按钮点击触发完整动画 FlatButton( onPressed: () { setState(() { isSignUp = !isSignUp; }); // 先重置控制器,避免重复点击导致动画状态混乱 _controller.reset(); _controller.forward(); }, )
额外提醒:如果用户可能多次点击按钮,建议在触发动画前调用_controller.reset(),避免动画状态叠加导致的异常。
内容的提问来源于stack exchange,提问作者Yechi
相关产品推荐
相关产品推荐

