Flutter中ScaleTransition嵌套FadeTransition动画无法正常工作
问题分析与解决
你的动画失效问题核心在于快速点击按钮时,动画控制器的状态没有被正确处理——当动画还在执行过程中,重复调用forward()或reverse()会导致动画状态混乱,因为默认情况下动画控制器不会中断正在进行的动画,进而出现缩放动画失效、表现异常的情况。
解决思路
- 处理动画平滑过渡:在
didUpdateWidget中,判断show状态变化时,使用animateTo()直接指定目标值(显示时到1.0,隐藏时到0.0),这样无论当前动画处于什么状态,都会平滑过渡到目标状态,避免状态冲突。 - 优化动画复用:由于缩放和淡入淡出动画的进度完全一致,可以复用同一个
Animation对象,减少冗余代码。
修正后的代码
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( home: Scaffold( body: Center( child: LogoScale(), ), ), ); } } class LogoScale extends StatefulWidget { const LogoScale({super.key}); @override State<LogoScale> createState() => LogoScaleState(); } class LogoScaleState extends State<LogoScale> { bool show = false; @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ElevatedButton( onPressed: (){ setState(() { show = !show; }); }, child: Text(show ? 'Hide Logo' : 'Show Logo'), ), Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ AnimationInOut( show: show, child: const FlutterLogo(size: 100.0,) ), ], ), ], ); } } class AnimationInOut extends StatefulWidget { final bool show; final Widget child; const AnimationInOut({super.key, required this.show, required this.child, }); @override State<AnimationInOut> createState() => AnimationInOutState(); } class AnimationInOutState extends State<AnimationInOut> with SingleTickerProviderStateMixin { late AnimationController animationController; late Animation<double> animation; @override void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 300)); // 初始化时设置对应状态的动画值 animationController.value = widget.show ? 1.0 : 0.0; // 复用同一个动画给缩放和淡入淡出 animation = animationController.drive(Tween<double>(begin: 0.0, end: 1.0)); } @override void dispose() { animationController.dispose(); super.dispose(); } @override void didUpdateWidget(AnimationInOut oldWidget) { super.didUpdateWidget(oldWidget); if (widget.show != oldWidget.show) { // 使用animateTo直接跳转到目标值,确保平滑过渡 animationController.animateTo( widget.show ? 1.0 : 0.0, duration: const Duration(milliseconds: 300), ); } } @override Widget build(BuildContext context) { return ScaleTransition( scale: animation, child: FadeTransition( opacity: animation, child: widget.child, ), ); } }
内容的提问来源于stack exchange,提问作者Serhii Ptitsyn
相关产品推荐
相关产品推荐

