Flutter中容器内容变化时如何实现尺寸平滑动画效果
问题根因
ScaleTransition布局时会直接采用子组件的原始尺寸计算自身占用空间,不会随缩放值动态调整大小,即使缩放值为0,也会提前占满Cancel文本的宽度,导致Row提前撑开、出现空白占位。
修复方案
替换ScaleTransition为SizeTransition实现横向展开动画,配合AnimatedContainer让按钮尺寸和文本显示同步过渡,不会出现提前占位的问题。
实现代码
首先在State中混入TickerProviderStateMixin,初始化两个动画控制器分别控制图标旋转、文本展开:
class SyncCancelButton extends StatefulWidget { const SyncCancelButton({super.key}); @override State<SyncCancelButton> createState() => _SyncCancelButtonState(); } class _SyncCancelButtonState extends State<SyncCancelButton> with TickerProviderStateMixin { late final AnimationController _rotationController; late final AnimationController _expandController; bool _isSyncing = false; @override void initState() { super.initState(); _rotationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); _expandController = AnimationController( vsync: this, duration: const Duration(milliseconds: 300), ); } @override void dispose() { _rotationController.dispose(); _expandController.dispose(); super.dispose(); } void _handleTap() { setState(() { _isSyncing = !_isSyncing; if (_isSyncing) { _rotationController.repeat(); _expandController.forward(); } else { _rotationController.stop(); _expandController.reverse(); } }); } @override Widget build(BuildContext context) { return GestureDetector( onTap: _handleTap, child: AnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.all(5.0), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), border: Border.all( color: Colors.pink.withOpacity(0.6), ), borderRadius: BorderRadius.circular(5.0), ), child: Row( mainAxisSize: MainAxisSize: MainAxisSize.min, children: [ RotationTransition( turns: _rotationController, child: const Icon( Icons.sync, color: Colors.pink, ), ), SizeTransition( sizeFactor: _expandController, axis: Axis.horizontal, axisAlignment: -1, child: Row( children: const [ SizedBox(width: 5), Text( "Cancel", style: TextStyle( color: Colors.pink, fontWeight: FontWeight.w600, ), ), SizedBox(width: 5), ], ), ), ], ), ), ); } }
实现效果
- 初始状态仅展示同步图标,无多余空白占位
- 点击按钮后,按钮宽度随Cancel文本平滑横向展开,同步图标开始旋转
- 再次点击触发取消,按钮平滑收缩回初始尺寸,图标停止旋转
如果需要增加文本淡入效果,可以在
SizeTransition的子组件外层嵌套FadeTransition,不要单独使用ScaleTransition包裹文本,否则会再次出现提前占位问题。
内容的提问来源于stack exchange,提问作者Sanketh B. K
相关产品推荐
相关产品推荐

