人生处万类,知识最为贤。这篇文章主要讲述Flutter 专题17 图解 ListView下拉刷新与上拉加载#yyds干货盘点#相关的知识,希望能为你提供帮助。
小菜上次尝试 ListView 异步加载列表数据时,用了三方库 flutter_refresh,这种方式使用很简单。但列表数据的加载也绝非一种,小菜这次准备用原生尝试一下。因为种种原因,小菜这次的整理距离上次时间很长,还是应该加强自控力。
小菜这次的列表并没有单独处理动画效果,只是对数据的刷新与加载更多进行正常加载进行处理,还需要进一步的学习研究。
文章图片
ListView + NotificationListener
小菜参考了很多大神的实现方式,发现 NotificationListener 很像 android 的滑动监听事件,再顶部和底部添加事件处理,集成方式也很简单。
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(新闻列表),
elevation: 0.0, // 阴影高度
),
body: new NotificationListener(
onNotification: dataNotification,
child: childWidget(),
),
);
}
文章图片
问题小结
一:如何区分列表滑动到顶部或底部? NotificationListener 中可以根据如下状态进行判断,并在相应的状态下进行需要的处理:
- (notification.metrics.extentAfter == 0.0) 为滑动到 底部;
- (notification.metrics.extentBefore == 0.0) 为滑动到 顶部。
bool dataNotification(ScrollNotification notification) { if (notification is ScrollEndNotification) { //下滑到最底部 if (notification.metrics.extentAfter == 0.0) { print(======下滑到最底部======); loadData(); } //滑动到最顶部 if (notification.metrics.extentBefore == 0.0) { print(======滑动到最顶部======); lastFileID = 0; rowNumber = 0; dataItems.clear(); loadData(); } } return true; }
二:监听的整个过程滑动中多次调用接口? 小菜在测试过程中每次滑动一下列表都会调用一次接口,因为在监听过程中若不做任何处理只要列表滑动便会进行监听,小菜的解决的方式有两种;
- 监听滑动到底部再进行业务操作调用接口,如问题一中的判断;
bool dataNotification(ScrollNotification notification) { if (notification is ScrollEndNotification) { //下滑到最底部 if (notification.metrics.extentAfter == 0.0) { print(======下滑到最底部======); loadData(); } } return true; }
- 尝试使用 TrackingScrollController,对滑动进行监听,这个类可用于同步两个或更多个共享单个 TrackingScrollController 的惰性创建的滚动视图的滚动偏移。它跟踪最近更新的滚动位置,并将其报告为其初始滚动偏移量。且在非底部时 maxScrollExtent 和 offset 值会相等。使用该类监听时更灵活,有些操作并非到底部才会进行处理等。
bool dataNotification(ScrollNotification notification) { if (notification is ScrollUpdateNotification) { if (_scrollController.mostRecentlyUpdatedPosition.maxScrollExtent > _scrollController.offset & & _scrollController.mostRecentlyUpdatedPosition.maxScrollExtent - _scrollController.offset < = 50) { loadData(); } } return true; }
三:异常情况处理? 小菜以前对列表的处理只包括列表数据为 0 时展示 Loading 等待页,有数据时展示数据列表,但是对于其他异常情况没有处理,这次特意添加上异常页面,这仅仅是业务方面的添加,没有新的技术点。
文章图片
主要源码
class LoadMoreState extends State<
LoadMorePage>
{
var lastFileID = 0;
var rowNumber = 0;
var cid = 29338;
var newsListBean = null;
List<
ListBean>
dataItems = <
ListBean>
[];
@override
void initState() {
super.initState();
loadData();
}// 请求首页数据
Future<
Null>
loadData() {
this.isLoading = true;
final Completer<
Null>
completer = new Completer<
Null>
();
getNewsData();
completer.complete(null);
return completer.future;
}getNewsData() async {
await http
.get(
https://XXX.....&
lastFileID=${lastFileID}&
rowNumber=${rowNumber})
.then((response) {
if (response.statusCode == 200) {
var jsonRes = json.decode(response.body);
newsListBean = NewsListBean(jsonRes);
setState(() {
if (newsListBean != null &
&
newsListBean.list != null &
&
newsListBean.list.length >
0) {
for (int i = 0;
i <
newsListBean.list.length;
i++) {
dataItems.add(newsListBean.list[i]);
}
lastFileID = newsListBean.list[newsListBean.list.length - 1].fileID.toString();
rowNumber += newsListBean.list.length;
} else {}
});
}
});
}bool dataNotification(ScrollNotification notification) {
if (notification is ScrollEndNotification) {
//下滑到最底部
if (notification.metrics.extentAfter == 0.0) {
print(======下滑到最底部======);
loadData();
}
//滑动到最顶部
if (notification.metrics.extentBefore == 0.0) {
print(======滑动到最顶部======);
lastFileID = 0;
rowNumber = 0;
dataItems.clear();
loadData();
}
}
return true;
}// 处理列表中是否有数据,对应展示相应页面
Widget childWidget() {
Widget childWidget;
if (newsListBean != null &
&
(newsListBean.success != null &
&
!newsListBean.success)) {
childWidget = new Stack(
children: <
Widget>
[
new Padding(
padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 100.0),
child: new Center(
child: Image.asset( images/icon_wrong.jpg, width: 120.0, height: 120.0, ),
),
),
new Padding(
padding: new EdgeInsets.fromLTRB(0.0, 100.0, 0.0, 0.0),
child: new Center(
child: new Text( 抱歉!暂无内容哦~, style: new TextStyle(fontSize: 18.0, color: Colors.blue), ),
),
),
],
);
} else if (dataItems != null &
&
dataItems.length != 0) {
childWidget = new Padding(
padding: EdgeInsets.all(2.0),
child: new ListView.builder(
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(6.0),
itemCount: dataItems == null ? 0 : dataItems.length,
itemBuilder: (context, item) {
return buildListData(context, dataItems[item]);
}),);
} else {
childWidget = new Center(
child: new Card(
child: new Stack(
children: <
Widget>
[
new Padding(
padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 35.0),
child: new Center( child: SpinKitFadingCircle( color: Colors.blueAccent, size: 30.0, ), ),
),
new Padding(
padding: new EdgeInsets.fromLTRB(0.0, 35.0, 0.0, 0.0),
child: new Center(child: new Text(正在加载中,莫着急哦~), ),
),
])),);
}
return childWidget;
}
}
【Flutter 专题17 图解 ListView下拉刷新与上拉加载#yyds干货盘点#】 小菜刚接触 Flutter 时间不长,还有很多不清楚和不理解的地方,如果又不对的地方还希望多多指出。
推荐阅读
- #私藏项目实操分享#iOS开发(NSSet的使用)
- (lks)SpringMvc底层+基础+自动装配
- 能让你更早下班的Python垃圾回收机制
- Divi Builder问题(后端不显示)
- 在首页上的不同区域显示前6个帖子WordPress()
- 显示不带html标签的产品变动价格
- 在WordPress中将帖子的类别名称显示为短代码的一部分
- 显示每个类别中的帖子数
- 在WordPress页面中以表格格式显示数据库中的数据