声明:本篇博客是上一篇博客的扩展,在原有的基础上实现下拉刷新和上拉加载更多功能。
地址:https://blog.csdn.net/weixin_43851639/article/details/100707373
下拉刷新
Flutter 框架中 RefreshIndicator 组件提供了下拉刷新的功能。使用该组件,需要实现一个刷新函数。
组件使用如下:
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.separated(
controller: _scrollController,
//下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,所以长度需要+1
itemCount: _list.length + 1,
itemBuilder: (BuildContext context, int index) => _buildRow(index),
//子项的分割线
separatorBuilder: (BuildContext context,int index) => Divider(),
),
),
刷新函数 _onRefresh() 代码如下,这里为了方便测试,直接删除列表的第一项元素:
//刷新数据
Future<Null> _onRefresh() async {
//刷新时间为3s
await Future.delayed(Duration(seconds: 3),(){
setState(() {
//为了测试,刷新后直接将_list第一项数据删除,实际中则是网络请求数据
_list.removeAt(0);
});
});
}
这样下拉刷新的功能就简单实现了。
效果如下:
上拉加载更多
上拉加载更多可能稍微复杂一点,不仅要考虑加载数据的问题,还要显示加载更多的提示,提高用户体验。
上拉加载更多是通过 ScrollController 来实现的。
定义如下:
//listview的控制器
ScrollController _scrollController = ScrollController();
并且需要为其添加监听:
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
print("上拉加载更多");
_getMore();
}
});
上拉加载需要一个提供数据的函数 _getMore() ,为了便于测试,这里随机添加原有数据,代码如下:
//上拉加载更多
Future<Null> _getMore() async {
Future.delayed(Duration(seconds: 1),() {
//为了测试,随机添加原有_list中的数据
setState(() {
_list.add(_list[1]);
for (int i=0; i<4; i++) {
int num = Random().nextInt(_list.length);
_list.add(_list[num]);
}
});
});
}
当数据为组后一条时,需要显示一个加载更多的组件:
//上拉加载更多组件
Widget _getMoreWidget() {
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
'加载中...',
style: TextStyle(fontSize: 16.0),
),
),
);
}
判断何时显示加载更多组件,何时显示原有数据项:
在这里插//构造listtile
Widget _buildRow(int index) {
if (index < _list.length) {
return Padding(
padding: EdgeInsets.all(20.0),
child: ListTile(
title: Text(_list[index].userName),
leading: CircleAvatar(
backgroundImage: NetworkImage("http://00.000.000.000:8080/images/" + _list[index].avatarUrl),
),
),
);
}
//此处显示加载更多组件
return _getMoreWidget();
}
需要注意的地方,ListView 中的 itemCount 需要在 _list 长度的基础上加1
//下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,长度需要+1
itemCount: _list.length + 1,
上拉加载更多效果如图:
完整代码如下:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:math';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.lightBlue,
),
home: ListviewHttp(),
);
}
}
class ListviewHttp extends StatefulWidget {
@override
ListviewHttpState createState() {
return new ListviewHttpState();
}
}
class ListviewHttpState extends State<ListviewHttp> {
List<ListData> _list = [];
//listview的控制器
ScrollController _scrollController = ScrollController();
//异步加载数据
_loadData() async {
String url = "http://00.000.000.000:8080/yiqijiu/GetHelpInfo";
http.Response response = await http.get(url);
setState(() {
final data = jsonDecode(response.body);
for (var _data in data) {
_list.add(ListData(_data["patientName"],_data["patientPortrait"]));
}
});
}
//构造listtile
Widget _buildRow(int index) {
if (index < _list.length) {
return Padding(
padding: EdgeInsets.all(20.0),
child: ListTile(
title: Text(_list[index].userName),
leading: CircleAvatar(
backgroundImage: NetworkImage("http://00.000.000.000:8080/images/" + _list[index].avatarUrl),
),
),
);
}
return _getMoreWidget();
}
//上拉加载更多组件
Widget _getMoreWidget() {
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text(
'加载中...',
style: TextStyle(fontSize: 16.0),
),
),
);
}
//初始化状态
@override
void initState() {
super.initState();
_loadData();
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
print("上拉加载更多");
_getMore();
}
});
}
//刷新数据
Future<Null> _onRefresh() async {
//刷新时间为3s
await Future.delayed(Duration(seconds: 3),(){
setState(() {
//为了测试,刷新后直接将_list第一项数据删除,实际中则是网络请求数据
_list.removeAt(0);
});
});
}
//上拉加载更多
Future<Null> _getMore() async {
Future.delayed(Duration(seconds: 1),() {
//为了测试,随机添加7条原有_list中的数据
setState(() {
_list.add(_list[1]);
for (int i=0; i<4; i++) {
int num = Random().nextInt(_list.length);
_list.add(_list[num]);
}
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Listview Http Test"),
),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.separated(
controller: _scrollController,
//下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,所以长度需要+1
itemCount: _list.length + 1,
itemBuilder: (BuildContext context, int index) => _buildRow(index),
//子项的分割线
separatorBuilder: (BuildContext context,int index) => Divider(),
),
),
);
}
}
//数据类,将json数据转换为对象
class ListData {
final String userName;
final String avatarUrl;
ListData(this.userName, this.avatarUrl);
}