Flutter:父组件状态更新时Modal Bottom Sheet不自动重绘问题
问题原因
showModalBottomSheet 的 builder 方法仅在弹窗初始化时执行一次,生成的弹窗组件拥有独立的 BuildContext,和父组件的状态更新完全隔离。父组件调用 setState() 只会刷新自身,无法触发已弹出的弹窗重绘,这就是数据加载完成后弹窗仍停留在进度指示器状态的原因。
解决方案
提供两种实用的解决方式:
方式一:弹窗内用 FutureBuilder 直接处理异步加载
让弹窗自行管理加载状态,无需依赖父组件存储状态,代码更解耦:
修改 _onButtonClick 方法:
void _onButtonClick(BuildContext context) { showModalBottomSheet( context: context, builder: (context) { return FutureBuilder<List<String>>( future: _namesRepository.loadNames(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasData) { return Column( children: snapshot.data!.map((name) => Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), child: Text(name), )).toList(), ); } else { return const Padding( padding: EdgeInsets.all(16.0), child: Text('加载失败,请重试'), ); } }, ); }, ); }
同时可以移除父组件 initState 中的加载逻辑,因为弹窗会自行请求数据。若需要缓存数据避免重复请求,可在父组件中保存加载结果,后续弹窗直接使用缓存值。
方式二:用 ValueNotifier + ValueListenableBuilder 监听状态变化
如果需要父组件提前加载数据并共享给其他组件,这种方式更合适:
- 将父组件中的
_names替换为ValueNotifier,用于监听数据变化:
class _HomeBodyState extends State<HomeBody> { final NamesRepository _namesRepository = NamesRepository(); final ValueNotifier<List<String>> _names = ValueNotifier([]); @override void initState() { super.initState(); _namesRepository.loadNames().then((names) => _names.value = names); } @override void dispose() { _names.dispose(); // 销毁避免内存泄漏 super.dispose(); } // 其他代码不变 }
- 修改弹窗的
builder,用ValueListenableBuilder监听_names的变化:
void _onButtonClick(BuildContext context) { showModalBottomSheet( context: context, builder: (context) { return ValueListenableBuilder<List<String>>( valueListenable: _names, builder: (context, currentNames, child) { if (currentNames.isEmpty) { return const Center(child: CircularProgressIndicator()); } else { return Column( children: currentNames.map((name) => Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), child: Text(name), )).toList(), ); } }, ); }, ); }
当 _names.value 更新时,ValueListenableBuilder 会自动触发弹窗重绘,更新显示内容。
内容的提问来源于stack exchange,提问作者Alex Angulo
相关产品推荐
相关产品推荐

