You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 监听状态变化

如果需要父组件提前加载数据并共享给其他组件,这种方式更合适:

  1. 将父组件中的 _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();
  }

  // 其他代码不变
}
  1. 修改弹窗的 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:05:38