ListView是flutter中线性排列的可滚动的列表部件。ListView 是最常用的滚动小部件。它在滚动方向上一个接一个地显示其子项。在交叉轴上,子项需要填满 ListView。
如果非空,则 itemExtent 会强制子项在滚动方向上具有给定的范围。
如果非空,则prototypeItem 会强制子项在滚动方向上具有与给定小部件相同的范围。 指定 itemExtent 或prototypeItem 比让子项确定自己的范围更有效,因为滚动机制可以利用对子项范围的预知来节省工作,例如当滚动位置发生剧烈变化时。 您不能同时指定 itemExtent 和prototypeItem,只能指定其中一个或不指定其中任何一个。
构建 ListView 有四种选项
1.默认构造函数采用显式 List<Widget> 子项
此构造函数适用于子项数量较少的列表视图,因为构造 List 需要为列表视图中可能显示的每个子项(而不仅仅是实际可见的子项)执行工作。默认 List 方式,是把数据添加到列表中,然后直接添加到 ListView。 Tips: 如果需要设置分割线,使用ListTile.divideTiles。
Dart
child: ListView(
padding: const EdgeInsets.all(8),
children: <Widget>[
Container(
height: 50,
color: Colors.amber[600],
child: const Center(child: Text("Entry A")),
),
Container(
height: 50,
color: Colors.amber[500],
child: const Center(child: Text("Entry B")),
),
Container(
height: 50,
color: Colors.amber[100],
child: const Center(child: Text("Entry C")),
)
],
)
2.ListView.builder 构造函数采用 IndexedWidgetBuilder,它根据需要构建子项
此构造函数适用于子项数量较多(或无限)的列表视图,因为仅对实际可见的子项调用构建器。
Dart
child: ListView.builder(
controller: _scrollController,
itemBuilder: (context, index) {
return Card(
child: Container(
height: 60,
alignment: Alignment.centerLeft,
child: Text("Item $index"),
),
);
},
itemCount: 200,
),
如果要添加分割线可以通过一个Column包裹Container和一个Divider。
Dart
child: ListView.builder(
controller: _scrollController,
itemBuilder: (context, index) {
return Card(
child:Column(
children: [
Container(
height: 60,
alignment: Alignment.centerLeft,
child: Text("Item $index"),
),
new Divider()
],
),
);
},
3.ListView.separated 构造函数采用两个 IndexedWidgetBuilder:itemBuilder 根据需要构建子项,separatorBuilder 类似地构建出现在子项之间的分隔符子项
此构造函数适用于子项数量固定的列表视图。通过 separatorBuilder 直接添加分割线。
Dart
final List<String> entries = <String>['C', 'Y', 'Z', 'Y'];
final List<int> colorCodes = <int>[600, 500, 300, 100];
child: ListView.separated(
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Colors.amber[colorCodes[index]],
child: Center(child: Text('Entry ${entries[index]}')),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: entries.length),
4.ListView.custom 构造函数采用 SliverChildDelegate,它提供了自定义子模型其他方面的功能。
例如,SliverChildDelegate 可以控制用于估计实际不可见的子项大小的算法。
Dart
List<String> entries = <String>['C', 'Y', 'Z', 'Y'];
class KeepAliveItem extends StatelessWidget {
const KeepAliveItem({
required Key super.key,
required this.data,
});
final String data;
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Text(data),
);
}
}
child: ListView.custom(
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return KeepAliveItem(
data: entries[index],
key: ValueKey<String>(entries[index]),
);
},
childCount: entries.length,
))
ScrollController
要控制滚动视图的初始滚动偏移,请提供一个已设置其 ScrollController.initialScrollOffset 属性的控制器(ScrollController)。
ScrollController:可用于控制此滚动视图滚动到的位置的对象。
ScrollController.initialScrollOffset:控制初始滚动位置。
Dart
final ScrollController _scrollController = ScrollController(initialScrollOffset: 120);
child: ListView.builder(
controller: _scrollController,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Container(
height: 60,
alignment: Alignment.centerLeft,
child: Text("Item $index"),
),
new Divider()
],
),
// child: Container(
// height: 60,
// alignment: Alignment.centerLeft,
// child: Text("Item $index"),
// ),
);
},
itemCount: 200,
)
效果如下,打开时会有120的偏移:(Item0上移了)
ScrollController.keepScrollOffset:用于控制滚动视图是否应自动保存和恢复其在 PageStorage 中的滚动位置。每次滚动完成时,使用 PageStorage 保存当前滚动偏移量,如果重新创建此控制器的可滚动项,则恢复它。
ScrollController.offset:用于读取当前滚动位置或更改它。(可以动态获取偏移量)
Dart
final ScrollController _scrollController = ScrollController();
_scrollController.addListener(() {
setState(() {
offset = _scrollController.offset;
isEnd = _scrollController.position.pixels ==
_scrollController.position.maxScrollExtent;
});
});
child: ListView.builder(
controller: _scrollController,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Container(
height: 60,
alignment: Alignment.centerLeft,
child: Text("Item $index"),
),
new Divider()
],
),
// child: Container(
// height: 60,
// alignment: Alignment.centerLeft,
// child: Text("Item $index"),
// ),
);
},
itemCount: 200,
)
如下图所示:position:114 表示上滑过程中计算出来的偏移量。
子元素的生命周期
Creation
在布局列表时,可见子元素、状态和渲染对象将基于现有小部件(例如使用默认构造函数时)或延迟提供的小部件(例如使用 ListView.builder 构造函数时)延迟创建。
Destruction
当子元素滚动出视图时,关联的元素子树、状态和渲染对象将被销毁。当滚动回时,列表中相同位置的新子元素将与新元素、状态和渲染对象一起延迟重新创建。