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

Flutter StaggeredGridView需热重载才显示问题修复

问题原因
  • FutureBuilder缺失必填的future参数,组件无法感知异步任务的执行状态,首次构建时永远走未完成分支,等数据实际加载完成后也没有触发UI重建,只有热重载触发强制刷新时才能拿到已经赋值的列表数据。
  • 页面初始化时从未调用数据加载方法oDB.convertList(),首次进入页面时destinationsList始终是空数组,没有触发网络拉取逻辑。
  • 原代码中ScrollPhysics()默认禁止列表滚动,内容超出屏幕后无法滑动,进度条也没有居中显示,交互体验存在问题。
修复方案

1. 修改页面State代码

在initState生命周期中初始化数据加载任务,给FutureBuilder传入对应的异步任务,补充状态判断和错误处理,修改后完整代码如下:

class _HomePageWidgetState extends State<HomePageWidget> {
  late Future<void> _dataInitFuture;

  @override
  void initState() {
    super.initState();
    _dataInitFuture = _loadPageData();
  }

  Future<void> _loadPageData() async {
    // 拉取Firestore节日数据
    await oDB.convertList();
    // 如果需要计算距离,先获取定位再执行计算逻辑
    // 示例:
    // Position userPosition = await locationProvider.getCurrentPosition();
    // await oDB.distanceCalculator(userPosition);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: const Color.fromRGBO(26, 31, 36, 80),
        automaticallyImplyLeading: false,
        title: const Text(
          'Festivals',
          style: TextStyle(
              color: Colors.white,
              fontSize: 30,
              fontWeight: FontWeight.w600,
              fontFamily: 'Poppins'),
          textAlign: TextAlign.center,
        ),
        actions: const [],
        centerTitle: false,
        elevation: 2,
      ),
      backgroundColor: const Color.fromRGBO(26, 31, 36, 80),
      body: SafeArea(
        child: FutureBuilder(
          future: _dataInitFuture,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            // 异步任务执行完成
            if (snapshot.connectionState == ConnectionState.done) {
              // 加载出错场景
              if (snapshot.hasError) {
                return Center(child: Text('加载失败:${snapshot.error}'));
              }
              return Container(
                padding: const EdgeInsets.all(16),
                child: StaggeredGridView.countBuilder(
                  crossAxisCount: 4,
                  itemCount: oDB.destinationsList.length,
                  // 替换为可滚动的物理配置
                  physics: const AlwaysScrollableScrollPhysics(),
                  mainAxisSpacing: 16,
                  crossAxisSpacing: 16,
                  itemBuilder: (context, index) => GestureDetector(
                      child: FestivalItem(oDB.destinationsList[index]),
                      onTap: () {
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => FestivalItemDetails(
                                    oDB.destinationsList[index])));
                      }),
                  staggeredTileBuilder: (index) => StaggeredTile.count(
                      (index % 7 == 0) ? 2 : 1, (index % 7 == 0) ? 2 : 1),
                ),
              );
            }
            // 加载中状态,进度条居中
            return const Center(child: CircularProgressIndicator());
          },
        ),
      ),
    );
  }
}

2. 优化DatabaseService冗余代码

convertList方法不需要嵌套多余的Future声明,简化后逻辑更清晰:

Future<void> convertList() async {
  destinationsList = await getDestinations();
  print(destinationsList);
}
注意事项
  • 不要在FutureBuilder的builder方法里直接初始化异步任务,否则每次页面rebuild都会重复触发网络请求,要提前在initState里把任务实例存好再传给FutureBuilder。
  • 如果需要定位计算距离,记得先申请定位权限,拿到有效Position对象后再调用distanceCalculator方法,避免权限报错。
  • 全局单例的oDB对象适合存全局共享数据,但数据更新后如果依赖setState/FutureBuilder刷新UI,要确保状态更新逻辑在当前页面的生命周期内触发。

内容的提问来源于stack exchange,提问作者broghalu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:57:20