前言
日常的开发工作中,经常会遇到列表中嵌套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,
),
],
)