在flutter中它可以使子组件沿一个方向上线性排列,并支持滚动。用ListView
实现滚动列表有多种方式,或可以设置children
属性,或利用构造方法ListView.builder
,或用构造 方法ListView.separated
。先来看其构造:
ListView({
super.key,
super.scrollDirection,//方向
super.reverse,//reverse为true时,那么滑动方向就是从右往左
super.controller,
super.primary,
super.physics,
super.shrinkWrap,
super.padding,
this.itemExtent,//每个子组件的高度
this.prototypeItem,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
super.cacheExtent,
List<Widget> children = const <Widget>[],
int? semanticChildCount,
super.dragStartBehavior,
super.keyboardDismissBehavior,
super.restorationId,
super.clipBehavior,
})
children
用ListView
的children
属性来实现一个滚动列表是最简单的一种实现方式。例子:
return Scaffold(
appBar: AppBar(title: const Text('ListView'),),
body: ListView(
shrinkWrap: false,
scrollDirection: Axis.vertical,
padding: const EdgeInsets.all(30),
itemExtent: 30,
children: const [
Text('1'),
Text('2'),
Text('3'),
Text('4'),
Text('5'),
Text('6'),
],
)
);
shrinkWrap
属性为false
时,代表ListView
会在布局方向上尽可能多的占用空间。shrinkWrap
值为true
时,则会根据子Widget
的大小来确定ListView
的大小,shrinkWrap
的值默认为false
。
ListView.builder
ListView.builder
适合列表项比较多或者列表项不确定的情况。
例子:
body: ListView.builder(
padding: const EdgeInsets.all(30),
itemCount: 30,//widget数量
itemExtent: 50,//widget高度
itemBuilder: (BuildContext context,int index){
return Text('$index');
}
),
itemBuilder
:它是列表项的构建器,类型为IndexedWidgetBuilder
,返回值为一个widget
。当列表滚动到具体的index
位置时,会调用该构建器构建列表项。itemCount
:列表项的数量,如果为null
,则为无限列表。
ListView.separated
ListView.separated
可以在生成的列表项之间添加一个分割组件,它比ListView.builder
多了一个separatorBuilder
参数,该参数是一个分割组件生成器。
例子:
body: ListView.separated(
padding: const EdgeInsets.all(30),
itemBuilder: (BuildContext context,int index){
return Container(
height: 50,
child: ListTile(title: Text('$index'),),
);
},
//设置分割线
separatorBuilder: (BuildContext context,int index){
return const Divider(color: Colors.black38,height: 1,);
},
itemCount: 30
),
下拉刷新
下拉刷新需要用RefreshIndicator
把ListView
包装一层,然后实现onRefresh
方法。
例子:
class ListViewPage extends StatefulWidget {
const ListViewPage({Key? key}) : super(key: key);
@override
State<ListViewPage> createState() => _ListViewPageState();
}
class _ListViewPageState extends State<ListViewPage> {
var itemCount = 30;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('滚动组件刷新'),),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.separated(
padding: const EdgeInsets.all(30),
itemBuilder: (BuildContext context,int index){
return Container(
height: 50,
child: ListTile(title: Text('$index'),),
);
},
separatorBuilder: (BuildContext context,int index){
return const Divider(color: Colors.black38,height: 1,);
},
itemCount: itemCount+1
),
),
);
}
Future _onRefresh(){
return Future.delayed(Duration(seconds: 1),(){
print('刷新完成');
setState((){
itemCount = 30;
});
});
}
}
上拉加载更多
上拉加载系统并没有给我们提供好组件,但是我们可以根据ListView
的controller
属性进行监听,等ListView
滚动至最后一个item
开始上拉加载操作。
完整例子:
class ListViewPage extends StatefulWidget {
const ListViewPage({Key? key}) : super(key: key);
@override
State<ListViewPage> createState() => _ListViewPageState();
}
class _ListViewPageState extends State<ListViewPage> {
var itemCount = 50;
//加载更多
var isLoading = false;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
// TODO: implement initState
_scrollController.addListener(() {
//监听滑动到最后
if(isLoading == false && _scrollController.position.pixels > _scrollController.position.maxScrollExtent){
setState(() {
isLoading = true;
_loadMore();
});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('滚动组件刷新'),),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.separated(
padding: const EdgeInsets.all(30),
controller: _scrollController,//监听
itemBuilder: (BuildContext context,int index){
if(index == itemCount){
return _getLoadMore();
}
return Container(
height: 50,
child: ListTile(title: Text('$index'),),
);
},
separatorBuilder: (BuildContext context,int index){
return const Divider(color: Colors.black38,height: 1,);
},
itemCount: itemCount+1
),
),
);
}
Widget _getLoadMore(){
if(isLoading == true){
return Container(
alignment: Alignment.center,
child: const SizedBox(
width: 25.0,
height: 25.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
}else{
return Container(
alignment: Alignment.center,
child: const Text('上拉加载'),
);
}
}
//上拉刷新
Future _onRefresh(){
return Future.delayed(Duration(seconds: 1),(){
print('刷新完成');
setState((){
itemCount = 50;
});
});
}
//下拉加载
Future _loadMore(){
// 请求接口
return Future.delayed(Duration(seconds: 2),(){
setState(() {
print('加载完成');
isLoading = false;
itemCount = 50;
});
});
}
}
添加固定列表头
class ListViewPage extends StatefulWidget {
const ListViewPage({Key? key}) : super(key: key);
@override
State<ListViewPage> createState() => _ListViewPageState();
}
class _ListViewPageState extends State<ListViewPage> {
var itemCount = 50;
//加载更多
var isLoading = false;
final ScrollController _scrollController = ScrollController();
@override
void initState() {
// TODO: implement initState
_scrollController.addListener(() {
//监听滑动到最后
if(isLoading == false && _scrollController.position.pixels > _scrollController.position.maxScrollExtent){
setState(() {
isLoading = true;
_loadMore();
});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('滚动组件刷新'),),
body: Column(
children: [
// const ListTile(title: Text('固定头部'),),
Container(
width: double.infinity,
height: 60,
color: Colors.yellow,
child: const ListTile(title: Text('固定头部'),),
),
Expanded(
child: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.separated(
padding: const EdgeInsets.all(30),
controller: _scrollController,//监听
itemBuilder: (BuildContext context,int index){
if(index == itemCount){
return _getLoadMore();
}
return Container(
height: 50,
child: ListTile(title: Text('$index'),),
);
},
separatorBuilder: (BuildContext context,int index){
return const Divider(color: Colors.black38,height: 1,);
},
itemCount: itemCount+1
),
),
),
],
),
);
}
Widget _getLoadMore(){
if(isLoading == true){
return Container(
alignment: Alignment.center,
child: const SizedBox(
width: 25.0,
height: 25.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
}else{
return Container(
alignment: Alignment.center,
child: const Text('上拉加载'),
);
}
}
//上拉刷新
Future _onRefresh(){
return Future.delayed(Duration(seconds: 1),(){
print('刷新完成');
setState((){
itemCount = 50;
});
});
}
//下拉加载
Future _loadMore(){
// 请求接口
return Future.delayed(Duration(seconds: 2),(){
setState(() {
print('加载完成');
isLoading = false;
itemCount = 50;
});
});
}
}