Flutter Provider中Consumer需返回null以实现FAB动画
解决Provider管理FAB显示隐藏且不重建Scaffold的问题
我刚好碰到过类似的场景,咱们一步步来搞定这个问题:
问题根源
Scaffold内置的FAB显示/隐藏动画只有当floatingActionButton参数从null切换到非null(或反过来)时才会触发。如果返回Offstage或Container,Scaffold会认为FAB一直存在,自然不会启动动画;而如果把整个Scaffold包在Consumer里,每次状态变化都会导致Scaffold重建,这也不符合你的需求。
正确实现方式
核心思路是:只让Consumer包裹FAB部分,而不是整个Scaffold。这样只有FAB相关的区域会根据状态重建,Scaffold的其他部分(AppBar、Body等)完全不受影响,同时还能触发内置动画。
1. 保留你的FABProvider
你的FABProvider实现是没问题的,继续用它就行:
class FABProvider extends ChangeNotifier { FABProvider(bool initialValue) { _visible = initialValue; } bool _visible; bool get visible => _visible; void hide() { if (_visible) { _visible = false; notifyListeners(); } } void show() { if (!_visible) { _visible = true; notifyListeners(); } } }
2. 在父组件中提供Provider
确保在Scaffold的上层(比如MaterialApp或者页面父组件)注入FABProvider:
ChangeNotifierProvider( create: (_) => FABProvider(true), // 初始状态设为显示FAB child: YourPage(), )
3. 在Scaffold中用Consumer单独包裹FAB
把Consumer放在floatingActionButton参数里,根据状态返回FAB或null:
Scaffold( appBar: AppBar(title: Text("Demo Page")), body: YourBodyWidget(), // 这个区域完全不会因FAB状态变化重建 floatingActionButton: Consumer<FABProvider>( builder: (context, fabProvider, child) { return fabProvider.visible ? FloatingActionButton( onPressed: () { // 示例:点击FAB隐藏自己 fabProvider.hide(); }, child: Icon(Icons.add), ) : null; }, ), )
额外优化(可选)
如果你的FAB有固定的子Widget(比如图标),可以把它放在Consumer的child参数里,避免每次重建都重新创建这个子Widget:
floatingActionButton: Consumer<FABProvider>( child: Icon(Icons.add), // 这个子Widget只会被创建一次 builder: (context, fabProvider, child) { return fabProvider.visible ? FloatingActionButton( onPressed: () => fabProvider.hide(), child: child, // 复用预创建的子Widget ) : null; }, ),
这样实现后,你就能达成所有需求:
- FAB显示/隐藏时触发Scaffold内置动画
- Scaffold的其他部分完全不会重建
- 符合Provider最小范围重建的最佳实践
内容的提问来源于stack exchange,提问作者Massimo Caroccia
相关产品推荐
相关产品推荐

