Flutter跨组件调用setState触发动画复位问题
问题原因
你的动画状态和全局业务状态完全脱节:
OptionsBarButton内部单独维护了_isPlaying标记控制动画,仅在自身被点击时才会切换动画方向- 粘贴按钮、后续要加的删除按钮等其他入口修改Provider状态切回信息展示态时,
OptionsBarButton根本没有感知到状态变化,自然不会执行reverse()复位动画 - 你写的
returnToMenuIcon()方法没有任何可被外部安全调用的路径,用GlobalKey直接拿子组件State调用方法的方案耦合度极高,后续维护很容易出问题,不推荐使用。
修复方案
把动画控制逻辑完全和Provider的全局状态绑定,不要在按钮内部维护独立的动画状态标记,直接监听Provider状态变化自动驱动动画即可,不需要额外暴露方法给外部调用。
修改OptionsBarButton组件
用Consumer包裹按钮组件监听状态变化,根据当前EditorState自动判断动画播放方向,去掉冗余的内部状态和无效方法:
class OptionsBarButton extends StatefulWidget { const OptionsBarButton({Key? key}) : super(key: key); @override State<OptionsBarButton> createState() => _OptionsBarButtonState(); } class _OptionsBarButtonState extends State<OptionsBarButton> with SingleTickerProviderStateMixin { late final AnimationController _controller; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 300)); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Consumer<OptionsBarProvider>( builder: (_, optionsController, __) { // 状态变化时自动控制动画方向 if (optionsController.state == EditorState.information) { _controller.reverse(); } else { _controller.forward(); } return IconButton( onPressed: () { if (optionsController.state == EditorState.options || optionsController.state == EditorState.copyMode) { optionsController.setState(EditorState.information); } else { optionsController.setState(EditorState.options); } }, icon: AnimatedIcon( icon: AnimatedIcons.menu_close, progress: _controller, )); }, ); } }
改动说明
- 删掉了内部独立维护的
_isPlaying标记,动画方向完全由全局业务状态决定:只要不是信息展示态,图标就保持叉号(动画正向完成状态);只要切回信息展示态,自动触发反向动画回到菜单图标 - 补全了之前缺失的动画控制器
dispose逻辑,避免内存泄漏 - 不管是点击切换按钮自身、点击粘贴按钮、还是后续新增的删除按钮,只要修改Provider状态切回信息展示态,按钮都会自动收到通知执行复位动画,组件间完全解耦,不需要跨组件调用内部方法
可选优化
你当前Provider里的setState方法和Flutter原生State类的setState方法重名,容易造成语义混淆,建议改成updateState之类的命名,可读性会更好。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

