聲明:本篇博客是上一篇博客的擴展,在原有的基礎上實現下拉刷新和上拉加載更多功能。
地址: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);
}