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

Flutter中widget滚动失效及HasSize报错问题咨询

滚动功能异常复现效果

问题根源

滚动失效+修改即触发HasSize报错的核心原因是嵌套滚动冲突+布局逻辑错误:

  • 你在CustomScrollView的Sliver布局体系中,嵌套了一个独立的普通GridView.count组件,两个可滚动组件会抢占滑动事件,导致外层滚动不响应
  • 你给嵌套的GridView包裹了固定高度690的SizedBox,破坏了Sliver体系的无界高度布局规则,只要调整滚动相关配置就会触发约束溢出的尺寸报错
  • 你把网格、普通组件全部塞在同一个SliverList的代理里,没有使用Sliver体系专用的网格组件,不符合CustomScrollView的布局要求
修复步骤
  1. 移除包裹GridView的固定高度SizedBox(height: 690)组件,硬编码高度是触发尺寸报错的核心诱因
  2. 把普通的GridView.count替换为Sliver体系专用的SliverGrid.count,直接放入CustomScrollView的slivers列表中,不要嵌套在普通SliverList的子组件代理里
  3. 将原来和网格混放的普通组件(顶部横幅、标题、底部加载按钮)拆分到独立的Sliver组件中,按钮用SliverToBoxAdapter包裹即可
  4. 如果排查阶段滚动仍异常,可以暂时移除ScrollConfiguration的自定义行为包裹,确认滚动正常后再补全自定义逻辑,避免自定义滚动行为拦截滑动事件
修复后核心代码
return Scaffold(
  body: Container(
    padding: const EdgeInsets.all(20),
    // 排查阶段可暂时注释ScrollConfiguration,确认滚动正常后再加回自定义行为
    // child: ScrollConfiguration(
    //   behavior: CustomScroll(),
      child: CustomScrollView(
        slivers: [
          // 原有SliverAppBar代码完全保留,不需要修改
          SliverAppBar(
            titleSpacing: 0,
            backgroundColor: background,
            floating: true,
            pinned: true,
            snap: false,
            centerTitle: false,
            elevation: 0,
            title: Container(
              alignment: Alignment.topLeft,
              padding: const EdgeInsets.only(top: 20, bottom: 20),
              child: const Text(
                'Teso esempio',
                style: TextStyle(
                    fontWeight: FontWeight.w600,
                    fontSize: 28,
                    color: primaryRed,
                    fontFamily: 'Proxima'),
              ),
            ),
            bottom: AppBar(
              titleSpacing: 0,
              elevation: 0,
              backgroundColor: background,
              toolbarHeight: 70,
              title: Row(
                children: [
                  Expanded(
                    child: Container(
                      padding: const EdgeInsets.only(right: 10),
                      child: TextFormField(
                        onTap: () async {
                          showSearch(
                            context: context,
                            delegate: Cerca(),
                          );
                        },
                        decoration: InputDecoration(
                          contentPadding: const EdgeInsets.all(10),
                          enabledBorder: OutlineInputBorder(
                            borderSide: const BorderSide(
                              color: border,
                            ),
                            borderRadius: BorderRadius.circular(10),
                          ),
                          focusedBorder: OutlineInputBorder(
                            borderSide: const BorderSide(
                                width: 1, color: Colors.red),
                            borderRadius: BorderRadius.circular(10),
                          ),
                          labelText: 'Cerca l\'oggetto',
                          prefixIcon: const Icon(Icons.search),
                        ),
                      ),
                    ),
                  ),
                  SizedBox.fromSize(
                    size: const Size(50, 50),
                    child: Material(
                      borderRadius:
                          const BorderRadius.all(Radius.circular(10)),
                      color: primaryRed,
                      child: InkWell(
                        splashColor: secondaryOrange,
                        onTap: () {},
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const [
                            Image(
                              image: AssetImage(
                                  'assets/images/icon/icon-filter.png'),
                              height: 20,
                            ),
                            Text(
                              "Filtra",
                              style: TextStyle(
                                  fontWeight: FontWeight.w600,
                                  fontSize: 12,
                                  color: Colors.white,
                                  fontFamily: 'Proxima'),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          // 普通非滚动组件单独放在SliverList中
          SliverList(
            delegate: SliverChildListDelegate([
              const SizedBox(
                height: 20,
              ),
              Container(
                decoration: const BoxDecoration(
                  borderRadius: BorderRadius.all(Radius.circular(10)),
                  color: secondaryOrange,
                ),
                height: 200,
              ),
              Container(
                alignment: Alignment.topLeft,
                padding: const EdgeInsets.only(top: 20),
                child: const Text(
                  'Ultimi annunci',
                  style: TextStyle(
                      fontWeight: FontWeight.w500,
                      fontSize: 28,
                      color: Colors.black,
                      fontFamily: 'Proxima'),
                ),
              ),
            ]),
          ),
          // 替换原固定高度GridView,使用Sliver专用网格组件
          SliverGrid.count(
            childAspectRatio: (itemWidth / itemHeight),
            padding: const EdgeInsets.only(top: 20, bottom: 20),
            crossAxisSpacing: 10,
            mainAxisSpacing: 10,
            crossAxisCount: 2,
            children: const <Widget>[
              AnnunciBox(colore: primaryRed),
              AnnunciBox(colore: primaryRed),
              AnnunciBox(colore: primaryRed),
              AnnunciBox(colore: primaryRed),
              AnnunciBox(colore: primaryRed),
              AnnunciBox(colore: primaryRed),
            ],
          ),
          // 底部加载按钮用SliverToBoxAdapter包裹
          SliverToBoxAdapter(
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10.0),
                ),
                primary: Colors.red,
                onPrimary: Colors.white,
                minimumSize: const Size(100, 50),
              ),
              onPressed: () {},
              child: const Text(
                'Carica altri annunci',
                style: TextStyle(
                    fontWeight: FontWeight.w500,
                    fontSize: 20,
                    color: Colors.white,
                    fontFamily: 'Proxima'),
              ),
            ),
          )
        ],
      ),
    // ),
  ),
);
注意事项
  • 所有放入CustomScrollView的列表/网格类组件,必须使用带Sliver前缀的专用组件(SliverList/SliverGrid等),不能直接嵌套普通ListView/GridView,否则必然出现滚动冲突和布局报错
  • Sliver体系下不要给子组件硬编码垂直方向的固定总高度,组件会自动根据内容计算布局尺寸,硬写高度很容易触发约束类报错
  • 后续如果需要加回自定义滚动行为,确保CustomScroll继承自ScrollBehavior,不要重写错误的方法拦截原始滑动事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:15:29