flutter中常用的列表组件为ListView、GridView和SliverList,本文将3种组件实现步骤和多种实现方式做个讲解。
一、ListView
能够实现静态加载和动态加载。所谓的静态加载就是需要设置好Listview所加载的子view,数量已定。所谓的动态加载就是子view数量不定。
1、静态加载
(1)源码属性:
有几个比较重要的属性:
- scrollDirection:滚动方向
- itemExtent :决定子view的高度或宽度。
- children :子view。
(2)使用:
class ListViewWidget1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('ListViewWidget1'),
),
body: ListView(
scrollDirection: Axis.vertical,
itemExtent: 80, //限制每一项的高度或宽度,即使子view设置了高度。
children: <Widget>[
Container(
height: 50,
color: Colors.red,
),
Container(
height: 50,
color: Colors.green,
),
Container(
height: 50,
color: Colors.blue,
),
],
),
);
}
}
在children中给指定要加载的子view。注意这里即使设置了子view的高度为50,由于itemExtent设置为80。所以子view的高度为80。
2、动态加载–ListView.builder
(1)源码属性:
有几个比较重要的属性:
- itemBuilder:用于加载子view
- itemCount:限制子view的个数。
(2)使用:
class ListViewWidget2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('ListViewWidget2'),
),
body: ListView.builder(
reverse: true,
itemBuilder: (context, index) {//index为子view下标。
return index % 2 == 0
? Container(
height: 50,
color: Colors.red,
)
: Container(
height: 50,
color: Colors.green,
);
},
itemCount: 100, //显示条目数量,不指定显示无限数量
itemExtent: 30,
),
);
}
}
现象就是两个色块交替显示,总共100条。
3、动态加载–ListView.separated
(1)源码属性:
有几个比较重要的属性:
- itemBuilder:用于加载子view
- itemCount:限制子view的个数。
- separatorBuilder:用于加载分割每个子view间的分割线。
(2)使用:
class ListViewWidget3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('ListViewWidget2'),
),
body: ListView.separated(
itemBuilder: (context, index) {
//item
return index % 2 == 0
? Container(
height: 50,
color: Colors.red,
)
: Container(
height: 50,
color: Colors.green,
);
},
separatorBuilder: (context, index) {
//分割线
return Divider(
height: 5,
color: Colors.black,
thickness: 5,
);
},
itemCount: 100));
}
}
现象就是两个色块交替显示,总共100条。每个子view之间有5px的黑色分割线。
4、动态加载–实现ListView分页加载
(1)先上代码吧,后面详解:
class ListViewWidget4 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return ListViewWidget4State();
}
}
class ListViewWidget4State extends State<ListViewWidget4> {
List<String> _datas = <String>[''];
//初始化数据
void _initData() {
//模拟网络加载,每次生成20条数据
Future.delayed(Duration(milliseconds: 100), () {
_datas.insertAll(_datas.length - 1,
generateWordPairs().take(20).map((e) => e.asPascalCase).toList());
//刷新数据
setState(() {});
});
}
@override
void initState() {
super.initState();
//初始化数据
_initData();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text('分页listView')),
body: ListView.builder(
itemBuilder: (context, index) {
if (_datas.length - 1 == index) {
if (_datas.length < 100) {
//最多加载100条
_initData();
return Container(
width: 10,
height: 10,
child: CircularProgressIndicator(),
);
} else {
return Center(
child: Container(
height: 20,
color: Colors.red,
child: Text(
('没有更多数据了'),
),
));
}
}
return ListTile(
//数据显示
title: Text(_datas[index]),
);
},
itemCount: _datas.length, //列表长度
),
);
}
}
由于我们需要刷新动态刷新列表数据的,所以这里使用StatefulWidget。通过_initData()方法来模拟网络加载,每次加载20条,通过第三方随机生成20个字符串。itemBuilder中限制最多加载100条,并且不足100条,每次下拉到最后一项都会再次生成20个字符串。
(2)效果:
二、GridView
1、静态加载–GridView
(1)源码属性:
有几个比较重要的属性:
- gridDelegate:用于控制每一行或每一列显示的子view个数,以及子view间距
- children : 子view列表
(2)使用:
class GridViewWidget1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('GridViewWidget1'),
),
body: GridView(
padding: EdgeInsets.all(10), //外边距
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //控制每一行显示的个数,子view的宽度自动计算
mainAxisSpacing: 5, //主轴方向的child间距
crossAxisSpacing: 5, //垂直轴方向的child间距
childAspectRatio: 2 //控制宽高比,此时表示高度为宽度的一半
),
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
],
),
);
}
}
现象就是每一行显示3个色块,总共显示2行,子view之间横向和纵向间距为5,注意 childAspectRatio 控制子view的显示宽高比。
2、静态加载–GridView.count
这种方式能够实现和上述方式一样的效果。
(1)源码属性:
注意这里的几个属性mainAxisSpacing、crossAxisSpacing、childAspectRatio就是之前方式gridDelegate的属性。
(2)使用:
class GridViewWidget2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('GridViewWidget3'),
),
body: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 5,
//主轴方向的child间距
crossAxisSpacing: 5,
//垂直轴方向的child间距
childAspectRatio: 2,
//子view
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
],
),
);
}
}
3、静态加载–GridView.extent
可以实现不指定每一行或每一列显示的个数,自动适配个数。
(1)源码属性:
重要属性:
- maxCrossAxisExtent:控制每一行显示多少个子view
(2)使用:
class GridViewWidget4 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('GridViewWidget4'),
),
body:
GridView.extent(maxCrossAxisExtent: 100, //指定每个子view的最大宽度,显示个数根据屏幕宽度而定
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.pink,
),
Container(
color: Colors.black,
),
Container(
color: Colors.yellow,
),
]),
);
}
}
4、动态加载–GridView.builder
(1)源码属性:
重要属性:
- gridDelegate:用于控制每一行或每一列显示的子view个数,以及子view间距
- itemBuilder:动态加载每一个子view
- itemCount:指定显示子view的个数
(2)使用:
class GridViewWidget3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('GridViewWidget3'),
),
body: GridView.builder(
itemCount: 11, //子view显示的个数
gridDelegate: //设置每一行显示3个
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (context, index) {
//加载每一个子view
return index % 2 == 0
? Container(
color: Colors.red,
)
: Container(
color: Colors.blue,
);
}));
}
}
三、SliverList–SliverFixedExtentList
这里只讲解SliverFixedExtentList。我们用它配合 SliverAppBar 实现android中 CollapsingToolbarLayout 的效果。
(1)使用:
class SliverListWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('SliverAppBar'),
backgroundColor: Colors.pinkAccent,
expandedHeight: 200,
floating: true,//floating 和snap同时设置为true,下拉会like显示flexibleSpace内容。
snap: true,
pinned: true,//appBar不会消失,一直在标题栏
flexibleSpace: FlexibleSpaceBar(//图片
background: Image.asset(
"assets/images/lock_bg.png",
fit: BoxFit.cover,
),
),
),
SliverFixedExtentList(//子view展示
itemExtent: 150,
delegate: SliverChildListDelegate.fixed([
Container(
color: Colors.red,
),
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
),
Container(
color: Colors.pink,
),
Container(
color: Colors.black,
),
Container(
color: Colors.yellow,
),
]))
],
),
);
}
}
(2)效果: