Flutter中如何实现圆形与矩形的出现缩放动画(按钮切换场景)
解决Flutter点击按钮切换形状并实现尺寸平滑过渡动画的问题
我来帮你梳理一下当前代码的问题,然后给出一个更简洁易理解的实现方案,完美满足你的需求:点击按钮切换圆形/矩形,新元素从小尺寸平滑过渡到目标尺寸,动画时长1秒。
你的代码存在的核心问题
- 子组件状态孤立:你把
Circle和Rectangle做成了独立的StatefulWidget,但它们内部的_checked状态从未被触发改变,所以AnimatedContainer根本不会执行动画——因为没有状态变化来驱动它。 - 组件替换而非属性变化:你用
if条件来切换显示不同的组件,这会直接移除旧组件、添加新组件,而AnimatedContainer的动画是基于同一个组件的属性变化来实现的,组件替换无法触发平滑过渡。
优化后的实现方案
我们可以把所有状态统一放在父组件MyButtonState中,用单个AnimatedContainer来完成形状、颜色和尺寸的动画过渡,这样逻辑更清晰,也更容易维护。
完整代码示例
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: MyButton(), ), )); } class MyButton extends StatefulWidget { @override MyButtonState createState() => MyButtonState(); } class MyButtonState extends State<MyButton> { // 记录当前显示的形状:'circle'/'rectangle',null表示未显示任何形状 String? _currentShape; // 控制AnimatedContainer的尺寸,初始为0(隐藏状态) double _shapeSize = 0; @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(40), child: Column( children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ TextButton( onPressed: () { // 先将尺寸重置为小尺寸,再切换形状并放大到目标尺寸 setState(() => _shapeSize = 100); Future.delayed(Duration(milliseconds: 100), () { setState(() { _currentShape = 'circle'; _shapeSize = 300; }); }); }, child: Text('Red Circle'), style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.red), foregroundColor: MaterialStateProperty.all(Colors.white), ), ), TextButton( onPressed: () { setState(() => _shapeSize = 100); Future.delayed(Duration(milliseconds: 100), () { setState(() { _currentShape = 'rectangle'; _shapeSize = 300; }); }); }, child: Text('Blue Rectangle'), style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.blue), foregroundColor: MaterialStateProperty.all(Colors.white), ), ), ], ), // 只有当_currentShape不为null时,才显示AnimatedContainer if (_currentShape != null) AnimatedContainer( width: _shapeSize, height: _shapeSize, decoration: BoxDecoration( // 根据当前形状切换颜色 color: _currentShape == 'circle' ? Colors.red : Colors.blue, // 根据当前形状切换形状 shape: _currentShape == 'circle' ? BoxShape.circle : BoxShape.rectangle, ), // 设置动画时长为1秒 duration: Duration(seconds: 1), // 设置动画曲线,让过渡更自然 curve: Curves.easeInOutCubic, ), ], ), ); } }
关键代码解释
- 状态管理:用
_currentShape记录当前显示的形状,_shapeSize控制容器尺寸,所有状态都在父组件中统一管理,避免了子组件状态孤立的问题。 - 动画触发逻辑:点击按钮时,先将尺寸重置为小尺寸(100),延迟100毫秒后切换形状并将尺寸放大到目标尺寸(300)——这样无论是首次显示还是切换形状,都会有从小尺寸平滑过渡到目标尺寸的效果。
- AnimatedContainer的作用:只要它的属性(尺寸、颜色、形状等)发生变化,就会自动根据
duration和curve执行平滑过渡动画,不需要额外的动画控制器,非常适合新手使用。
额外说明
如果你希望首次点击按钮时,形状从0直接放大到300,只需要把按钮点击事件里的代码改成:
onPressed: () { setState(() { _currentShape = 'circle'; _shapeSize = 300; }); },
初始_shapeSize是0,点击后直接变300,同样会有平滑的放大动画。
内容的提问来源于stack exchange,提问作者Gizmor
相关产品推荐
相关产品推荐

