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

Flutter含两个ListView时如何实现下半区内容整体滚动

问题核心

你当前布局失效的原因是:Expanded包裹ListView的写法会强制内部ListView占满父组件剩余可用高度,两个ListView各自持有独立的滚动上下文,无法和中间穿插的文本标题形成统一的整体滚动效果。

实现方案

根布局直接使用Column即可满足Part I固定不滚动的要求:第一层子组件放筛选、排序功能区,第二层子组件放Part II的整体滚动容器。以下提供两种可直接落地的实现方式,按需选择即可。

方案1:CustomScrollView + SliverList(性能最优,推荐长列表使用)

用CustomScrollView作为Part II的统一滚动容器,所有标题、列表项都作为Sliver子组件接入,不存在嵌套滚动冲突,长列表场景下性能表现最好。

Column(
  children: [
    // Part I 固定筛选排序区,不会随下方内容滚动
    Container(
      padding: const EdgeInsets.all(16),
      child: const Text("排序、筛选组件区"),
    ),
    // Part II 整体滚动区
    Expanded(
      child: CustomScrollView(
        slivers: [
          // 第一行标题 Atrasadas (2)
          const SliverPadding(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            sliver: SliverToBoxAdapter(
              child: Text(
                "Atrasadas (2)",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ),
          // 第一个待办列表,无独立滚动逻辑
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(title: Text("Atrasadas 项 $index")),
              childCount: 2, // 替换为实际列表长度
            ),
          ),
          // 第二行标题 A tiempo(2)
          const SliverPadding(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            sliver: SliverToBoxAdapter(
              child: Text(
                "A tiempo(2)",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ),
          // 第二个待办列表,无独立滚动逻辑
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(title: Text("A tiempo 项 $index")),
              childCount: 2, // 替换为实际列表长度
            ),
          ),
        ],
      ),
    )
  ],
)

方案2:保留原有ListView结构改配置(改造成本最低,适合短列表)

如果不想重构现有ListView代码,只需移除包裹两个ListView的Expanded,给ListView添加两个关键参数,外层套统一的滚动容器即可:

  • shrinkWrap: true:让ListView根据子项总高度自适应布局,不再强制占满父级剩余高度
  • physics: const NeverScrollableScrollPhysics():禁用ListView自身的滚动响应,滚动事件全部交给外层容器处理
Column(
  children: [
    // Part I 固定筛选排序区
    Container(
      padding: const EdgeInsets.all(16),
      child: const Text("排序、筛选组件区"),
    ),
    // Part II 整体滚动区
    Expanded(
      child: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // 第一个标题
            const Padding(
              padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: Text(
                "Atrasadas (2)",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            // 第一个ListView 自适应高度+禁用自身滚动
            ListView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: 2,
              itemBuilder: (context, index) => ListTile(title: Text("Atrasadas 项 $index")),
            ),
            // 第二个标题
            const Padding(
              padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: Text(
                "A tiempo(2)",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            // 第二个ListView 自适应高度+禁用自身滚动
            ListView.builder(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemCount: 2,
              itemBuilder: (context, index) => ListTile(title: Text("A tiempo 项 $index")),
            ),
          ],
        ),
      ),
    )
  ],
)

注意:方案2中shrinkWrap: true会一次性计算并渲染所有列表项,列表长度超过100条时会出现性能问题,长列表场景优先选方案1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 00:33:35