前言
日常的开发工作中,经常会遇到列表中嵌套ListView的需求。具体情况也分为两种。
1.竖向ListView嵌套横向ListView
常见的需求:竖向ListView行数不限制,横向ListView的列数不限制。具体情况如下图。

代码如下:
ListView(
children: [
Text('ListView'),
Stack(
children: [
IgnorePointer(
child: Opacity(
opacity: 0.0,
child: Item(),
),
),
SizedBox(width: double.infinity),
Positioned.fill(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (_, index) => Item(),
),
),
],
),
],
)Stack存在无Positioned包裹的子组件,决定Stack尺寸的是无位置的组件中的最大的尺寸,Positioned不会影响Stack的尺寸。(当然如果子类全部是Positioned包裹的子组件,Stack会将自身尺寸设置为父级布局约束所允许的最大尺寸,为对齐子组件创造条件。)。
此处用Positioned.fill,让ListView尽量占满整个Stack。
接下来设置宽度,利用SizedBox的向下传递约束,向上传递尺寸的特性。用SizedBox(width: double.infinity)把宽度撑开到整个屏幕的宽度。
接下来算出Item的高度,用Item的高度撑开Stack的高度。
此处用Item的初衷只是为了定制高度,不能让Item显示在屏幕上,所以用Opacity隐藏Item,为了忽略掉事件响应,最后用上IgnorePointer。
2.竖向ListView嵌套竖向ListView
这类需求是由于父列表和子列表的行数都不确定。处理也比较简单。
ListView(
children: [
Text('ListView'),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (_, index) => Item(),
),
],
)通过设置shrinkWrap来固定ListView的高度,禁用滑动事件,让外面的ListView响应滑动事件就行了。
需要注意的是使用shrinkWrap,会一次性加载出所有的Item。如果数量太多,会出现内存问题。这时候可以通过父ListView和子ListView共用一个ScrollController来解决。代码如下:
ScrollController _scrollController;
ListView(
controller: _scrollController,
children: [
ListView(
controller:_scrollController,
),
],
)