介绍
线性排列的可滚动列表。
核心属性
ListView({
Key? key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController? controller,
bool? primary,
ScrollPhysics? physics,
bool shrinkWrap = false,
EdgeInsetsGeometry? padding,
this.itemExtent,
this.prototypeItem,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double? cacheExtent,
List<Widget> children = const <Widget>[],
int? semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
String? restorationId,
Clip clipBehavior = Clip.hardEdge,
})
- scrollDirection
设置滚动方向,其值有:
enum Axis {
/// 水平方向滚动,默认
horizontal,
/// 竖直方向滚动
vertical,
}
- controller
滚动控制器。能够获取滚动相关信息 - primary
当内容不足以滚动时,是否支持滚动;true:用来解决listView不满一页无法触发下拉刷新,需要注意这个时候不可以设置controller - physics:控制用户滚动视图的交互,可以提供边界回弹特效
- AlwaysScrollableScrollPhysics:列表总是可滚动的。在iOS上会有回弹效果,在android上不会回弹。那么问题来了,如果primary设置为false(内容不足时不滚动),且 physics设置为AlwaysScrollableScrollPhysics,列表也是是可以滑动的
- PageScrollPhysics:一般是给PageView控件用的滑动效果。如果listview设置的话在滑动到末尾时会有个比较大的弹起和回弹
- ClampingScrollPhysics:滚动时没有回弹效果,同android系统的listview效果
- NeverScrollableScrollPhysics:就算内容超过列表范围也不会滑动
- BouncingScrollPhysics:不论什么平台都会有回弹效果
- shrinkWrap
默认false:则高度为滑动方向上的最大允许高度;如果在滑动方向上没有设置约束,则这个字段必须设置为true,否则会报错。简而言之就是父节点为滑动组件的时候,且滑动方向一致需要true,例如:SingleChildScrollView。 - padding
内边距 - itemExtent
指定Item在滑动方向上的高度,用来提高滑动性能。指定了该属性后,Item自己定的高度将失效。 - prototypeItem
指定Item在滑动方向上的高度为prototypeItem属性的widget的高度,用来提高滑动性能。指定了该属性后,Item自己定的高度将失效。 - addAutomaticKeepAlives
是否将子控件包裹在AutomaticKeepAlive控件内。 - addRepaintBoundaries
是否将子控件包裹在 RepaintBoundary 控件内。用于避免列表滚动时的重绘,如果子控件重绘开销很小时,比如子控件就是个色块或简短的文字,把这个字段设置为false性能会更好 - cacheExtent
可见区域的前后会有一定高度的空间去缓存子控件,当滑动时就可以迅速呈现 - children
子控件数组
示例
ListView有四种使用方式:
- ListView()
默认构造方法,可以在子组件比较少时使用,因为不管子组件是否可见,都会创建出所有child。
ListView(
children: [
Container(
height: 300,
color: Colors.pink,
child: const Center(child: Text("This is a item1"),),
),
Container(
height: 300,
color: Colors.teal,
child: const Center(child: Text("This is a item2"),),
),
Container(
height: 300,
color: Colors.amber,
child: const Center(child: Text("This is a item3"),),
),
],
);
- ListView.builder()
这种方式属于懒加载方式,比较常用。传参数跟ListView()差不多,区别是没有children属性,代替的是 itemBuilder 和 itemCount
- itemBuilder:IndexedWidgetBuilder Function类型,创建子组件
- itemCount:item数量
ListView.builder(itemBuilder: (context, index) {
Color? color;
if (index % 2 == 0) {
color = Colors.pink;
} else if (index % 3 == 0) {
color = Colors.teal;
} else if (index % 5 == 0) {
color = Colors.amber;
}
return Container(
height: 100,
color: color,
child: Center(child: Text("This is a item:$index"),),
);
}, itemCount: 50, itemExtent: 200,);
- ListView.separated()
跟ListView.builder()差不多,可以设置分割线,需要传一个separatorBuilder。
ListView.separated(
itemBuilder: (context, index) {
Color? color;
if (index % 2 == 0) {
color = Colors.pink;
} else if (index % 3 == 0) {
color = Colors.teal;
} else if (index % 5 == 0) {
color = Colors.amber;
}
return Container(
height: 100,
color: color,
child: Center(
child: Text("This is a item:$index"),
),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
itemCount: 50,
);
- ListView.custom()
这个是比较高阶的用法了,可以自己去实现子控件的复用重绘。这里就不展开说了
-
childrenDelegate:SliverChildDelegate;有两个默认实现SliverChildListDelegate,SliverChildBuilderDelegate;方式1实际上内部实现是SliverChildListDelegate,方式2,3内部实现是SliverChildBuilderDelegate;
效果图: