Flutter列表视图ListView的4种创建方式及使用实例
ListView 是一个线性布局的widgets列表,可以使用水平布局,也可以使用垂直布局(默认)。
接下来我们来看如何在Flutter中创建和使用ListView。
创建ListView
我们可以使用多种方式创建ListView对象。
1. 直接使用ListView的构造函数
默认构造函数有一个children参数,它接受一个Widget数组列表(List)。
这种方式适合只有少量的子组件的情况,因为这种方式需要将所有子widget都提前创建好,而不是等到子widget真正显示的时候再创建,也就是说通过默认构造函数构建的ListView没有应用基于Sliver的懒加载模型。如果列表长度非常长,直接创建大量子widget可能会引起内存问题。
使用 ListView(children: List) 的优点是简单,直接生成一个 List 的列表,然后赋值给 ListView 的 children 参数即可,例如:
List<Widget> getListChildren() {
return [new Text("第一条"), new Text("第二条"), new Text("第三条")];
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: new ListView(
children: getListChildren(),
shrinkWrap: true,
padding: const EdgeInsets.all(25.0),
itemExtent: 50,
),
);
}
}
我们来看ListView的构造函数:
ListView({
Key key,
Axis scrollDirection = Axis.vertical,//列表的滚动方向,默认是垂直方向
bool reverse = false,
ScrollController controller,//控制器,与列表滚动相关,比如监听列表的滚动事件
bool primary,
ScrollPhysics physics,//列表滚动至边缘后继续拖动的物理效果,Android与iOS效果不同。
bool shrinkWrap = false,//该属性将决定列表的长度是否仅包裹其内容的长度。当ListView嵌在一个无限长的容器组件中时,shrinkWrap必须为true,否则Flutter会给出警告
EdgeInsetsGeometry padding,//列表内边距
this.itemExtent,//子元素长度。当列表中的每一项长度是固定的情况下可以指定该值,有助于提高列表的性能
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,//预渲染区域长度,ListView会在其可视区域的两边留一个cacheExtent长度的区域作为预渲染区域(对于ListView.build或ListView.separated构造函数创建的列表,不在可视区域和预渲染区域内的子元素不会被创建或会被销毁)
List<Widget> children = const <Widget>[],//子元素的数组列表
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
})
可以看到,使用构造函数创建ListView还是非常简单的,但只适用于列表元素较少的情况。
2. ListView.builder
ListView.builder利用IndexedWidgetBuilder来按需构造。这种方式适合于具有大量(或无限)子视图的列表视图(因为它只创建当前可见的列表元素)。也就说通过该构造函数创建的ListView是支持基于Sliver的懒加载模型的。
方法及参数:
ListView.builder({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
this.itemExtent,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
})
ListView.builder 新增了两个重要参数:
- itemCount:这个参数声明了list的长度,这个值表明ListView中会存在多少个子项,null则表示无限列表。
- itemBuilder:它是列表项的构建器,类型为IndexedWidgetBuilder,返回值为一个widget。当列表滚动到具体的index位置时,会调用该构建器构建列表项。(接受 context(构造的上下文) 和 index(当前索引) 两个参数)
示例,创建一个无限列表:
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
padding: const EdgeInsets.all(25),
itemExtent: 50,
itemBuilder: (context, index) {
return new Text("第$index行");
},
),
);
}
}
3. ListView.separated
如果列表子项之间需要分割线,此时我们可以用ListView的separated方法来创建列表。
函数定义:
ListView.separated({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required IndexedWidgetBuilder itemBuilder,
@required IndexedWidgetBuilder separatorBuilder,
@required int itemCount,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
})
ListView.separated可以在生成的列表项之间添加一个分割组件,它采用两个IndexedWidgetBuilder:itemBuilder根据需要构建子项separatorBuilder类似地构建出现在子项之间的分隔符子项。此构造函数适用于具有固定数量的子控件的列表视图。
示例:
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.separated(
itemCount: 1000,
itemBuilder: (context, index) {
return new Center(child: new Text("第$index行"));
},
separatorBuilder: (context, index) {
return Divider(
height: 1,
color: Colors.green,
);
},
),
);
}
}
4. ListView.custom
使用ListView.custom的SliverChildDelegate构造,它提供了定制子模型的其他方面的能力。 例如,SliverChildDelegate可以控制用于估计实际上不可见的孩子的大小的算法。通常我们使用上面介绍的3种方式就足够了,这里对custom不做过多介绍了。
小结
本节我们学习了Flutter中,最常用的视图之一——列表视图的创建及使用方法。
我们可以使用ListView的4种构造方法来创建一个列表视图,并根据自己的需要来进行个性化配置。