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

Flutter中Expanded失效致GridView Builder无法扩展引发UI空白

解决方案

你的问题出在嵌套冗余Column导致布局约束冲突,以及Stack内加载提示的布局错误,以下是具体修复步骤:

1. 移除嵌套的Column

原代码中body内的Container的child是一个Column,而这个Column的children里又套了一个Column,这会导致内部Column无法正确接收父级约束,Expanded无法正常分配剩余空间。直接将内部Column的内容移到外层Column下即可。

2. 修复Stack内的加载提示布局

原代码里用Padding包裹Positioned.fill是错误的,Positioned必须直接作为Stack的子元素才能生效。将加载提示改为直接用Positioned定位。

3. 确保GridView正确配置

保持GridView的shrinkWrap: false(默认值),通过Expanded让它占据Slider和横向ListView之后的剩余可用高度。

修改后的关键代码片段

@override
Widget build(BuildContext context) {
  Size size = MediaQuery.of(context).size;
  return Scaffold(
    drawer: DrawerMenu(),
    appBar: PostHomeAppBar(appBar: AppBar()),
    body: Stack(
      children: [
        Container(
          height: double.infinity,
          width: double.infinity,
          decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage("lib/assets/asset/bg-original (1).png"),
              fit: BoxFit.cover
            )
          ),
          // 移除嵌套Column,直接放置组件
          child: Column(
            children: [
              /// slider
              Container(
                height: size.height * 0.25,
                width: double.infinity,
                child: MySlider(),
              ),

              const SizedBox(height: 5),

              /// list view builder
              Container(
                height: 55,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,
                  itemCount: _homePageController.getGameCategorylist?.data?.length ?? 0,
                  itemBuilder: (BuildContext context, int index) {
                    bool isSelected = _selectedTabIndex == index;
                    return Obx(
                      () => (_homePageController.isLoading.value)
                          ? const Center(child: Loader())
                          : _homePageController.getGameCategorylist!.data == null
                              ? const Center(child: Text(''))
                              : Padding(
                                  padding: const EdgeInsets.only(left: 2, right: 2, top: 4, bottom: 8),
                                  child: GestureDetector(
                                    onTap: () => _onTappedItem(index),
                                    child: FittedBox(
                                      child: Container(
                                        padding: const EdgeInsets.only(left: 10, right: 10),
                                        decoration: BoxDecoration(
                                          color: isSelected ? AppColors.golden : null,
                                          gradient: isSelected
                                              ? null
                                              : const LinearGradient(
                                                  colors: [Color(0xff1e1b53), Color(0xff444185)],
                                                  begin: Alignment.topCenter,
                                                  end: Alignment.bottomCenter,
                                                ),
                                          borderRadius: BorderRadius.circular(30),
                                        ),
                                        child: Column(children: [
                                          SizedBox(height: size.height * 0.01),
                                          Text(
                                            _homePageController.getGameCategorylist!.data![index].lobbyCat.toString(),
                                            textAlign: TextAlign.center,
                                            style: const TextStyle(
                                                fontWeight: FontWeight.w400,
                                                color: Colors.white,
                                                fontFamily: 'Roboto',
                                                fontSize: 8),
                                          ),
                                          Text(
                                            '(${_homePageController.getGameCategorylist!.data![index].length.toString()})',
                                            textAlign: TextAlign.center,
                                            style: const TextStyle(
                                                fontWeight: FontWeight.w400,
                                                color: Colors.white,
                                                fontFamily: 'Roboto',
                                                fontSize: 8),
                                          ),
                                          SizedBox(height: size.height * 0.005),
                                        ]),
                                      ),
                                    ),
                                  ),
                                ),
                    );
                  },
                ),
              ),

              /// grid view builder
              Expanded(
                child: GridView.builder(
                  padding: EdgeInsets.zero,
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    crossAxisSpacing: 2,
                    mainAxisSpacing: 2,
                    mainAxisExtent: 120,
                  ),
                  itemCount: casinoGameList?.data?.length ?? 0,
                  itemBuilder: (BuildContext context, int index) {
                    return Obx(() => (_homePageController.isLoading.value)
                        ? const Center(child: Loader())
                        : casinoGameList?.data == null
                            ? const Center(child: Text(''))
                            : GestureDetector(
                                onTap: () {
                                  final gameData = casinoGameList?.data?[index];
                                  Get.to(() => WebViewHome(gameData ?? Datum()));
                                },
                                child: Padding(
                                  padding: const EdgeInsets.all(4.0),
                                  child: Container(
                                    alignment: Alignment.center,
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(10),
                                      image: DecorationImage(
                                        image: NetworkImage(base + '${casinoGameList?.data?[index].imgSrc.toString()}'),
                                        fit: BoxFit.cover,
                                      ),
                                    ),
                                  ),
                                ),
                              ));
                  },
                ),
              ),
            ],
          ),
        ),
        // 修复加载提示布局
        if (_isLoading)
          const Positioned.fill(
            child: Center(child: Loader()),
          ),
      ],
    ),
    bottomNavigationBar: BottomNavigationBar(
      backgroundColor: const Color(0xff140b36),
      currentIndex: _currentIndex,
      onTap: (int index) => setState(() => _currentIndex = index),
      selectedItemColor: Colors.amber,
      unselectedItemColor: Colors.grey,
      type: BottomNavigationBarType.fixed,
      items: [
        BottomNavigationBarItem(
          icon: GestureDetector(
            onTap: () => Get.to(() => Home_Post_Login()),
            child: Image.asset('lib/assets/asset/icon_home_fill.png',
                color: _currentIndex == 0 ? Colors.amber : Colors.white, height: 20),
          ),
          label: 'HOME',
        ),
        BottomNavigationBarItem(
          icon: GestureDetector(
            onTap: () => Get.to(() => Login_Screen()),
            child: Image.asset('lib/assets/asset/icon_games.png',
                color: _currentIndex == 1 ? Colors.amber : Colors.white, height: 20),
          ),
          label: 'PROVIDERS',
        ),
        BottomNavigationBarItem(
          icon: GestureDetector(
            onTap: () => Get.to(() => WebViewHome(Datum(gameTypeUnified: 'game_shows'))),
            child: Image.asset('lib/assets/asset/icon_game_show.png',
                color: _currentIndex == 2 ? Colors.amber : Colors.white, height: 20),
          ),
          label: 'GAME SHOWS',
        ),
        BottomNavigationBarItem(
          icon: GestureDetector(
            onTap: () => Get.to(() => Profile()),
            child: Image.asset('lib/assets/asset/icon_user.png',
                color: _currentIndex == 3 ? Colors.amber : Colors.white, height: 20),
          ),
          label: 'MY ACCOUNT',
        ),
      ],
    ),
  );
}

核心原理说明

  • Column是垂直方向布局组件,直接在其下使用Expanded时,Expanded会自动占据除固定高度组件外的剩余空间。
  • 嵌套Column会打破约束传递,内部Column默认试图占据无限高度,导致Expanded无法计算可用空间,最终出现空白。
  • Stack中的Positioned.fill会让加载提示覆盖整个屏幕,确保加载状态显示正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:12:37