简介
listview是flutter中最常用的滚动组件之一,可以非常方便的实现一个方向上的多个子组件的线性排列。先看一下它的默认构造函数:
ListView({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
this.itemExtent,
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:列表滚动的方向,可选Axis.vertical、Axis.horizontal代表竖向滑动和横向滑动,默认竖向。
- reverse:是否倒序显示 ,默认为正序显示。
- controller:listview的控制器,可以用来监听滑动状态。
- physics:physics有几个可选项,
AlwaysScrollableScrollPhysics() | 总是可以滑动 |
NeverScrollableScrollPhysics() | 禁止滚动 |
BouncingScrollPhysics() | 内容超过一屏,拉到顶部有回弹效果 |
ClampingScrollPhysics() | 包裹内容,不会有回弹 |
- shrinkWrap:列表的长度是否只包裹其内容的长度,默认为false。注意,当listview包含于一个长度不确定的组件中必须设为true,否则将会报错。
- children:存放子元素的组件数组。
简单介绍了一些常用的参数,下面来看一下常用的使用方法。
默认构造方法
默认构造方法的子元素是直接写在children列表里面的,它接受的是Widget。这种方式比较适合元素比较少的情况,对于子元素差异大的情况也很好用。
ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: <Widget>[
new Text('item1'),
new Text('item2'),
new Text('item3'),
],
);
ListView.builder
new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return getItem(index);
},
itemCount: data.length,
itemExtent: 50.0, //强制高度为50.0
shrinkWrap: true,
physics: BouncingScrollPhysics(),
)
- itemBuilder:子元素的构建器,参数有context和index(当前列表位置),返回值为一个widget。当列表滚动到具体的index位置时,会调用该构建器构建列表项。
- itemCount:子项的数量,这里返回了测试数据的长度。当不使用此参数时listview元素是无限的。
重写initState方法,添加测试数据:
List data = [];
@override
void initState() {
super.initState();
setState(() {
for (int i = 0; i < 100; i++) {
data.add("item $i");
}
});
}
接着是构造子元素的getItem方法,这里使用了GestureDetector处理点击事件,toast则是使用了 fluttertoast: ^3.1.3包。
Widget getItem(int index) {
return new GestureDetector(
onTap: () {
//处理点击事件
showToast(data[index]);
},
child: new Container(
padding: const EdgeInsets.all(14.0),
child: new Text(data[index]),
),
);
}
ListView.separated
ListView.separated与ListView.builder的主要区别是它提供了生成分割线的一个必填参数separatorBuilder,示例如下:
new ListView.separated(
itemBuilder: (BuildContext context, int index) {
return getItem(index);
},
separatorBuilder: (BuildContext context, int index) {
return new Divider(
endIndent: 50,
height: 1,
thickness: 1,
);
},
itemCount: data.length,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
)
Divider即是分割线,参数有
- height:分割线占用的高度。
- thickness:分割线的厚度。
- indent:分割线起点端留白长度。
- endIndent:分割线终点端留白长度。
- color:线的颜色。
另外:itemCount在这种模式下是必填参数,与ListView.builder不同。ListView.builder的方式要
添加分割线的话可以在itemBuilder中添加(即添加到子元素中)。
完整示例
最后贴上完整的示例代码:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:fluttertoast/fluttertoast.dart';
void main() {
runApp(new ListViewApp());
}
class ListViewApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
theme: ThemeData.light(),
home: new ListViewWidget(),
title: "listViewSample",
);
}
}
class ListViewWidget extends StatefulWidget {
@override
ListState createState() => new ListState();
}
class ListState extends State<ListViewWidget> {
List data = [];
@override
void initState() {
super.initState();
setState(() {
for (int i = 0; i < 100; i++) {
data.add("item $i");
}
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
appBar: new AppBar(
backgroundColor: Colors.blue,
title: new Center(
child: new Text('listViewTitle'),
),
),
body: new Column(
children: [
new Expanded(
child: new ListView.separated(
itemBuilder: (BuildContext context, int index) {
return getItem(index);
},
separatorBuilder: (BuildContext context, int index) {
return new Divider(
endIndent: 50,
height: 1,
thickness: 1,
);
},
itemCount: data.length,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
)),
],
));
}
Widget getItem(int index) {
return new GestureDetector(
onTap: () {
//处理点击事件
showToast(data[index]);
},
child: new Container(
padding: const EdgeInsets.all(14.0),
child: new Text(data[index]),
),
);
}
void showToast(String toast) {
Fluttertoast.showToast(
msg: toast,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
);
}
}
运行效果: