Flutter-ListView组件
1. ListView基础
1.1 ListView基本使用
ListView可以沿一个方向(垂直或水平方向,默认是垂直方向)来排列其所有子Widget。
一种最简单的使用方式是直接将所有需要排列的子Widget放在ListView的children属性中即可。
我们来看一下直接使用ListView的代码演练:
-
为了让文字之间有一些间距,我使用了Padding Widget
image.png
1.2 ListTile的使用
在开发中,我们经常见到一种列表,有一个图标或图片(Icon),有一个标题(Title),有一个子标题(Subtitle),还有尾部一个图标(Icon)。
这个时候,我们可以使用ListTile来实现:
class MyHomeBody extends StatelessWidget {
final TextStyle textStyle = TextStyle(fontSize: 20,color: Colors.redAccent);
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.people,size: 36,),
title: Text("联系人"),
subtitle: Text("联系人信息"),
trailing: Icon(Icons.arrow_forward_ios),
),
ListTile(
leading: Icon(Icons.email,size: 36,),
title: Text("邮箱"),
subtitle: Text("邮箱地址信息"),
trailing: Icon(Icons.arrow_forward_ios),
),
ListTile(
leading: Icon(Icons.message,size: 36,),
title: Text("消息"),
subtitle: Text("消息详情信息"),
trailing: Icon(Icons.arrow_forward_ios),
),
ListTile(
leading: Icon(Icons.map,size: 36,),
title: Text("地址"),
subtitle: Text("地址详情信息"),
trailing: Icon(Icons.arrow_forward_ios),
),
],
);
}
}
image.png
1.3 垂直方向滚动
我们可以通过设置 scrollDirection 参数来控制视图的滚动方向。
我们通过下面的代码实现一个水平滚动的内容:
- 这里需要注意,我们需要给Container设置width,否则它是没有宽度的,就不能正常显示。
- 或者我们也可以给ListView设置一个itemExtent,该属性会设置滚动方向上每个item所占据的宽度。
class MyHomeBody extends StatelessWidget {
final TextStyle textStyle = TextStyle(fontSize: 20,color: Colors.redAccent);
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
// itemExtent: 200,
children: <Widget>[
Container(color: Colors.redAccent,width: 200,),
Container(color: Colors.green,width: 200,),
Container(color: Colors.blue,width: 200,),
Container(color: Colors.purple,width: 200,),
Container(color: Colors.orange,width: 200,),
],
);
}
}
image.png
2. ListView.build
通过构造函数中的children传入所有的子Widget有一个问题:默认会创建出所有的子Widget。
但是对于用户来说,一次性构建出所有的Widget并不会有什么差异,但是对于我们的程序来说会产生性能问题,而且会增加首屏的渲染时间。
我们可以ListView.build来构建子Widget,提供性能。
2.1. ListView.build基本使用
ListView.build适用于子Widget比较多的场景,该构造函数将创建子Widget交给了一个抽象的方法,交给ListView进行管理,ListView会在真正需要的时候去创建子Widget,而不是一开始就全部初始化好。
该方法有两个重要参数:
- itemBuilder:列表项创建的方法。当列表滚动到对应位置的时候,ListView会自动调用该方法来创建对应的子Widget。类型是IndexedWidgetBuilder,是一个函数类型。
- itemCount:表示列表项的数量,如果为空,则表示ListView为无限列表。
class MyHomeBody extends StatelessWidget {
final TextStyle textStyle = TextStyle(fontSize: 20,color: Colors.redAccent);
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 100,
itemExtent: 80,
itemBuilder: (BuildContext context,int index){
return ListTile(
title: Text("标题$index"),
subtitle: Text("详情内容--$index"),
);
}
);
}
}
image.png
2.2 ListView.build动态数据
在之前,我们搞了一个test.json数据,我们现在动态的来通过JSON数据展示一个列表。
思考:这个时候是否依然可以使用StatelessWidget:
答案:不可以,因为当前我们的数据是异步加载的,刚开始界面并不会展示数据(没有数据),后面从JSON中加载出来数据(有数据)后,再次展示加载的数据。
- 这里是有状态的变化的,从无数据,到有数据的变化。
- 这个时候,我们需要使用StatefulWidget来管理组件。
class MyHomeBody extends StatefulWidget {
@override
_MyHomeBodyState createState() => _MyHomeBodyState();
}
class _MyHomeBodyState extends State<MyHomeBody> {
List<Anchor> anchors = [];
@override
void initState() {
Anchor().getAnchors().then((anchors){
setState(() {
this.anchors = anchors;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: anchors.length ??0 +1,
itemBuilder: (BuildContext context,int index){
return Padding(
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.network(
anchors[index].imageUrl,
fit: BoxFit.fitWidth,
width: MediaQuery.of(context).size.width,
),
SizedBox(height: 8,),
Text(anchors[index].nickName,style: TextStyle(fontSize: 20),),
SizedBox(height: 5,),
Text(anchors[index].roomName,style: TextStyle(fontSize: 16),),
],
),
);
},
);
}
}
image.png
2.3. ListView.separated
ListView.separated可以生成列表项之间的分割器,它除了比ListView.builder多了一个separatorBuilder参数,该参数是一个分割器生成器。
下面我们看一个例子:奇数行添加一条蓝色下划线,偶数行添加一条红色下划线:
class MyHomeBody extends StatelessWidget {
final Divider blueColorDiv = Divider(color: Colors.blue,);
final Divider redColorDiv = Divider(color: Colors.red,);
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (BuildContext context,int index){
return ListTile(
leading: Icon(Icons.people),
title: Text("联系人${index+1}"),
subtitle: Text("联系人电话 -- 1008${index+1}"),
);
},
separatorBuilder: (BuildContext context,int index){
return index % 2 == 0 ? redColorDiv : blueColorDiv;
},
itemCount: 100
);
}
}
image.png
学习内容来自Flutter从入门到实战