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

Flutter:如何在可滚动Column中放置高度自适应的水平ListView.builder?

问题:Flutter中可滚动Column内的水平列表行被压缩,无法按实际高度排列

我想在可滚动的Column里展示多个从数据库获取数据的水平滚动列表行,列表项高度不一(部分为两行文本,部分为单行)。但使用SliverFillRemaining组件后,各列表行被强制压缩/拉伸,无法按内容实际高度排列,求解决方案。


现有代码

页面代码

Widget build(BuildContext context) {
    return const Scaffold(
      body: SafeArea(
        child: CustomScrollView(
          slivers: [
            SliverFillRemaining(
              child: Column(
                children: [
                  Flexible(
                    flex: 1,
                    child: ScrollElement(),
                    fit: FlexFit.loose,
                  ),
                  Flexible(
                    flex: 1,
                    child: ScrollElement(),
                    fit: FlexFit.loose,
                  ),
                  Flexible(
                    flex: 1,
                    child: ScrollElement(),
                    fit: FlexFit.loose,
                  ),
                  Flexible(
                    flex: 1,
                    child: ScrollElement(),
                    fit: FlexFit.loose,
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

ScrollElement组件代码

@override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          Container(
            padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  "Section",
                  style: cH2Style.copyWith(color: cTextColor),
                ),
              ],
            ),
          ),
          Flexible(
            fit: FlexFit.tight,
            child: ListView.builder(
              shrinkWrap: true,
              scrollDirection: Axis.horizontal,
              itemCount: elements.length < 3 ? elements.length : 3,
              itemBuilder: (context, index) {
                final element = Element.fromDocument(elements[index]);
                return Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    ElementWidget(),
                    const Padding(
                      padding: EdgeInsets.only(right: 20),
                    )
                  ],
                );
              },
            ),
          ),
        ],
      ),
    );
  }

ElementWidget组件代码

Widget build(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width / 2,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ClipRRect(
            borderRadius: BorderRadius.circular(10),
            child: AspectRatio(
              aspectRatio: 1,
              child: Image.asset("assets/images/testbild.jpg"),
            ),
          ),
          Text("..."),
        ],
      ),
    );
  }

解决方案

问题核心在于SliverFillRemaining会强制子组件填充剩余空间,配合Flexible的flex比例分配,导致每个ScrollElement被强制拉伸到相同高度,完全忽略内部列表项的实际高度。按以下步骤修改:

  1. 移除SliverFillRemaining和Flexible
    直接用SliverToBoxAdapter包裹每个ScrollElement,让每个区块根据自身内容高度自适应,不再被强制分配空间。

  2. 简化ScrollElement内部结构
    去掉包裹水平ListView的Flexible,因为shrinkWrap: true已经让ListView根据内容计算高度,无需强制填充。

修改后的页面代码

Widget build(BuildContext context) {
  return Scaffold(
    body: SafeArea(
      child: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(child: ScrollElement()),
          SliverToBoxAdapter(child: ScrollElement()),
          SliverToBoxAdapter(child: ScrollElement()),
          SliverToBoxAdapter(child: ScrollElement()),
        ],
      ),
    ),
  );
}

修改后的ScrollElement代码

@override
Widget build(BuildContext context) {
  return Container(
    child: Column(
      children: [
        Container(
          padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                "Section",
                style: cH2Style.copyWith(color: cTextColor),
              ),
            ],
          ),
        ),
        // 移除Flexible,直接保留ListView
        ListView.builder(
          shrinkWrap: true,
          scrollDirection: Axis.horizontal,
          itemCount: elements.length < 3 ? elements.length : 3,
          itemBuilder: (context, index) {
            final element = Element.fromDocument(elements[index]);
            return Padding(
              padding: const EdgeInsets.only(right: 20),
              child: ElementWidget(),
            );
          },
        ),
      ],
    ),
  );
}

额外说明

  • 如果水平列表需要滚动功能,保持默认physics即可;若不需要内部滚动,可添加physics: const NeverScrollableScrollPhysics()。
  • ElementWidget中的mainAxisSize: MainAxisSize.min已保证子组件只占用必要高度,无需额外调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:54:55