📅  最后修改于: 2023-12-03 15:30:49.883000             🧑  作者: Mango
在Flutter中,ListView是用于构建可滚动列表的一个重要组件。ListView允许我们在屏幕上展示大量的数据,并提供了诸多的用来优化性能和用户交互的选项。其中,ListView.builder是ListView中比较常用的构造方法。
ListView.builder基于数据源的长度构建一个列表。这个列表的所有子项都由builder函数来生成,builder函数会在每次子项需要更新时调用。ListView.builder适用于当我们需要很多相似的子项时,比如从一个数组或者数据库中生成子项的列表。
ListView.builder的构造方法如下:
ListView.builder({
Key? key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController? controller,
bool? primary,
ScrollPhysics? physics,
required IndexedWidgetBuilder itemBuilder,
int? itemCount,
bool shrinkWrap = false,
EdgeInsetsGeometry? padding,
String? restorationId,
Clip clipBehavior = Clip.hardEdge
})
参数列表:
| 参数 | 类型 | 描述 | |----------------|-------------------------|------------------------------------------------| | key | Key? | widget的标识符 | | scrollDirection| Axis | 滚动方向,可为Axis.vertical(默认)或Axis.horizontal | | reverse | bool | 是否反转滚动方向 | | controller | ScrollController? | 滚动控制器 | | primary | bool? | 当为true时,滚动将停止到边界处 (默认值为null) | | physics | ScrollPhysics? | 与此滚动视图相关联的physics | | itemBuilder | IndexedWidgetBuilder | 子项构造器,需要返回一个widget | | itemCount | int? | 列表项数量,必须指定 | | shrinkWrap | bool | 内容适合的情况下是否需要缩小 | | padding | EdgeInsetsGeometry? | ListView的内边距,如果没有指定,则默认为EdgeInsets.zero | | restorationId | String? | 存档和恢复的ID | | clipBehavior | Clip | 裁剪行为 |
在使用ListView.builder之前,首先要确定数据源和itemBuilder函数。假设我们有一个包含字符串的数组,需要把它们渲染为一个ListView。
final List<String> items = ['item 1', 'item 2', 'item 3', 'item 4', 'item 5'];
然后,我们需要编写builder函数。builder函数的目的是将每个列表项渲染为widget。ListView.builder构造函数中的itemBuilder参数特别重要,它需要一个IndexedWidgetBuilder类型的函数。IndexedWidgetBuilder是一个具有以下签名的函数:
Widget Function(BuildContext context, int index)
这个函数需要两个参数:BuildContext context和int index。context是当前BuildContext,通常作为widget创建的上下文。index是列表项的索引,它从0开始递增。在builder函数中我们需要将在items中读取给定索引值的item,并将其渲染为一个Widget。
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item),
);
},
)
上面的代码将items中的每个元素转换为一个ListTile并返回。
ListView.builder提供了一些属性和方法来优化性能。
我们可以使用ScrollController来控制滚动的位置和初始位置,同时也可以用ScrollController监听滚动事件。暴露在外的ScrollController指向ListView中的滚动位置并将其控制。
final controller = ScrollController();
@override
void initState() {
super.initState();
controller.jumpTo(100.0); // 控制初始位置
}
@override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller, // 将滚动控制器指向ListView
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
);
}
我们还可以在列表底部追加新的数据,这时候我们需要监听滚动到底事件,然后添加新数据到items,然后使用setState()调用来重新构建ListView。
final controller = ScrollController();
@override
void initState() {
super.initState();
controller.addListener(_scrollListener);
}
@override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
if (controller.offset >= controller.position.maxScrollExtent &&
!controller.position.outOfRange) {
setState(() {
// 在当前items追加新数据
items.addAll(['item 6', 'item 7', 'item 8', 'item 9', 'item 10']);
});
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller,
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item),
);
},
);
}
ListView.builder支持两种缓存机制:itemExtent和addAutomaticKeepAlives。
itemExtent属性定义每个列表项的大小。它允许创建一个具有固定大小的子项,这样Flutter就不需要在每次创建列表项时都重新计算它的大小。
ListView.builder(
itemCount: items.length,
itemExtent: 50, // 每个子项的高度都是50
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item),
);
},
)
addAutomaticKeepAlives保存了Widget状态以在滚动视图中保留它们的位置。假设我们在itemBuilder中添加RepaintBoundary,将可持续化它的状态,这可以避免在滚动过程中不必要的重绘。不过它的使用需要谨慎,因为保持项会占用更多的内存。
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item),
leading: RepaintBoundary(
child: Icon(Icons.favorite), // 可持续化状态
),
);
},
addAutomaticKeepAlives: true, // 开启自动保持
)
precacheExtent属性用于在滚动视图滚过页面末尾之前缓存指定数量的列表项。这可以减少滚动视图的等待时间,但需要谨慎使用。通常它会在缓存超出级别时造成无意义的列表构建,从而反而降低了性能。
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: Text(item),
);
},
cacheExtent: 50, // 缓存50个列表项到内存
)
ListView.builder是在Flutter开发中非常重要的组件。它通过一个builder函数来根据提供的数据源动态渲染列表项,为我们的开发提供了很大的便利。当我们需要构建大量、相似的子项时,ListView.builder是最优秀的选择之一,我们还可以通过控制滚动位置、动态追加列表项、缓存和预取数据等方法对其进行性能优化。