ListView 是 ScrollView 的子类,很多参数在 Fluter 滚动的基石 Scrollable 中已经讲过了,一些与 Scrollable 重合,这里只讲下 ListView 新加的参数。
itemExtent
每个 child 的高度。设置了这个参数,内部用 SliverFixedExtentList 创建 child,性能会得到提高。如果要使用这个参数的话,要求每个 child 的高度都是一样高的。即使不一样高,也会强制成一样高。
prototypeItem
如果非空,则 prototypeItem 强制子项在滚动方向上具有与给定 widget 相同的高度。内部调用 SliverPrototypeExtentList 创建 child,性能会得到提高。
itemBuilder
按需 create child。比如 Viewport 内可以显示 10 个 child,初始化完成后,ListView 就只 create 前 10 个 child(可能会再多几个,取决于 cacheExtent),滚动列表的时候,再 create 新的 child,旧的 child 会被销毁。用这种方式可以保证 ListView 的性能。
separatorBuilder
把 child 间隔开。显示的时候,每显示一个 child ,接着就会显示一个 separator。
itemCount
列表的数量。可以为空,代表数据无限。在可以给出数量的情况下,一定要给出数量。
addAutomaticKeepAlives
默认为 true,把 child 用 AutomaticKeepAlive 包起来。AutomaticKeepAlive 允许后代 widgets 控制子树是否实际保持活动状态。
if (addAutomaticKeepAlives) {
child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child));
}
AutomaticKeepAlive 最终用 KeepAlive 把 child 包起来。KeepAlive 将无条件地使子树保持活动状态。
Widget build(BuildContext context) {
return KeepAlive(
keepAlive: _keepingAlive,
child: _child,
);
}
让 KeepAlive 成为需要保留的 list child widget 子树的根 widget。 KeepAlive widget 将子树的 top render object child 标记为保持活动状态。当渲染对象滚出视图时,该列表会将子渲染对象(以及其关联的元素和状态)保存在缓存列表中,而不是销毁它们。当滚动回视图时,渲染对象将按原样重新绘制(如果在此期间未将其标记为 dirty)。
简单来说,想保持状态 addAutomaticKeepAlives 设为 true,不想保持 设为 false。
addRepaintBoundaries
默认为 true。用 RepaintBoundary 把 child 包起来。RepaintBoundary 为其子项创建一个单独的显示列表,如果子树的重绘时间与树的周围部分不同,则可以提高性能。
if (addRepaintBoundaries) {
child = RepaintBoundary(child: child);
}
keyboardDismissBehavior
默认为 ScrollViewKeyboardDismissBehavior.manual
。键盘不会自动收回。下面的示例修改为 ScrollViewKeyboardDismissBehavior.onDrag
, 当 Listview 滑动的时候,键盘自动收起。
ListView.builder(
itemCount: 50,
itemBuilder: (context, index) {
if (index == 5) {
return const TextField();
} else {
return ListTile(
title: Text('$index'),
);
}
},
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
);
默认构造函数 ListView
ListView({
...
List<Widget> children = const <Widget>[],
childrenDelegate = SliverChildListDelegate(
children,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
addSemanticIndexes: addSemanticIndexes,
),
如果列表是已知的,可以直接全部给出,适合用 默认构造函数。
ListView(
children: List.generate(
60,
(index) => ListTile(
title: Text('$index'),
)),
);
ListView.separated
childrenDelegate = SliverChildBuilderDelegate(
(BuildContext context, int index) {
final int itemIndex = index ~/ 2;
final Widget widget;
if (index.isEven) {
widget = itemBuilder(context, itemIndex);
} else {
widget = separatorBuilder(context, itemIndex);
assert(() {
if (widget == null) {
throw FlutterError('separatorBuilder cannot return null.');
}
return true;
}());
}
return widget;
},
ListView.separated 构造函数需要两个 builder。itemBuilder 用来 build 正文 widget,separatorBuilder 用来 build 分隔 widget
ListView.separated(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text('$index'));
},
separatorBuilder: (context, index) => const Divider(color: Colors.black,)
);
ListView.builder
这是最常用的构造函数,可以让数据无限,ListView 只显示其中一部分数据。
itemCount,itemBuilder 是必须的。
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title:Text('$index'),
);
},
);
前面对参数有讲解,为了提高性能,最好能指定 itemExtent,或 prototypeItem。
ListView.custom
ListView.custom 是为了让你能自己决定 childrenDelegate。比如我们可以 选择 SliverChildListDelegate。
ListView.custom(
childrenDelegate: SliverChildListDelegate(List.generate(
60,
(index) => ListTile(
title: Text('index'),
))));
这样就和默认的 ListView 构造函数一样了。
我们还可以选择 SliverChildBuilderDelegate,可以实现 ListView.builder、 ListView.separated 的功能。
相比于直接用 Scrollable, ListView 用起来挺方便的,但也是有代价的,失去了一些灵活性,后面的文章会讲。
今天就到这里了,谢谢观看。