Flutter Column 嵌套 ListView/Column,解决滑动冲突报错

开发 Flutter 项目中碰到一个常见需求,Column 嵌套 ListView ,这种 UI 设计很常见,但我们实现起来就要考虑嵌套后滑动冲突的问题。

滑动

先分享 Column 内容滑动和滚动的使用,如果我们的布局在垂直内容很长,超出屏幕,直接运行,是会报错的。

A RenderFlex overflowed by *** pixels on the bottom.

这个超出屏幕的报错很常见,相信都见过。我们需要加一个滚动控件 SingleChildScrollView 包裹。

  body: SingleChildScrollView(
    child: Column(
      children: [
        Container(
          height: 300,
          color: Colors.yellow,
        ),
        Container(
          height: 300,
          color: Colors.red,
        ),
        ...
      ],
    ),
  ),

嵌套 ListView

但如果往里面嵌套一个 ListView ,就会报如下错误。

RenderBox was not laid out: RenderViewport#80017 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1979 pos 12: 'hasSize'

这是因为 ListView在滚动方向上尽可能占据最大空间。而 Column 会要求每一个 Child Widget 有一个明确的高度。当 ListView 嵌套在 Column 里面当做子控件时,它们俩的需求就矛盾了。Column 希望子控件给它一个具体高度,ListView 希望占据最大的高度,需求相互矛盾,就报错了。

那我们给 ListView 外层添加一个高度,这个问题就解决了。

SizedBox(
  height: 200,
  child: buildListView()
)

Widget buildListView() {
  return ListView.builder(
    itemBuilder: (context, index) {
      return ListTile(title: Text(_items[index]));
    },
    itemCount: _items.length,
  );
}

设置一个明确的高度虽然可以解决问题,但如果 ListView 内容超过高度限制,就会在高度里滚动,在这个小范围内滑动。这应该不会满足我们的需求,我们需要 ListView 在整个页面上下滑动,随着屏幕滚动。

再说回 ListView ,它的默认特点是占据最大高度,但可以通过 shrinkWrap 属性设置,让它只占据内容高度,也就是内容计算出来多高,就占据多高。有点像 Android 开发里的 match_parentwrap_content

  ListView.builder(
    shrinkWrap: true,
    ...
  );	

shrinkWrap 默认值是 false,占据最大高度,设置成 true 会包裹内容,占据包裹内容高度。

上面代码运行后,还是不对,因为 ListView 滑动还是只会在小范围内滑动,不会拖动整个屏幕,再加上下面属性。

  ListView.builder(
    shrinkWrap: true,
    physics: NeverScrollableScrollPhysics(),
    ...
  );	

所有问题都解决了,实际布局中 ListView 会自动给下方加一个间距,手动设置 padding 解决。

  ListView.builder(
    shrinkWrap: true,
    physics: NeverScrollableScrollPhysics(),
    padding: EdgeInsets.zero,
    ...
  );	

嵌套 Column

如果将上面的 ListView 换成 Column ,也就是 Column 里面 嵌套 Column ,也会报上面的错。因为 Column 默认也会占据最大高度,设置子 Column 的主轴,从 max 设置到 min。

Column(
  children: [
    Column(
      mainAxisSize: MainAxisSize.min
    )
  ],
),

OK,希望以上内容对你有用。

本文由老郭种树原创,转载请注明:https://guozh.net/column-nested-listview/

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注