博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flutter 18: 图解 ListView 下拉刷新与上拉加载 (二)【NotificationListener】
阅读量:6427 次
发布时间:2019-06-23

本文共 5003 字,大约阅读时间需要 16 分钟。

      小菜上次尝试 ListView 异步加载列表数据时,用了三方库 ,这种方式使用很简单。但列表数据的加载也绝非一种,小菜这次准备用原生尝试一下。因为种种原因,小菜这次的整理距离上次时间很长,还是应该加强自控力。

      小菜这次的列表并没有单独处理动画效果,只是对数据的刷新与加载更多进行正常加载进行处理,还需要进一步的学习研究。

ListView + 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 中可以根据如下状态进行判断,并在相应的状态下进行需要的处理:

  1. (notification.metrics.extentAfter == 0.0) 为滑动到 底部
  2. (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;}
二:监听的整个过程滑动中多次调用接口?

      小菜在测试过程中每次滑动一下列表都会调用一次接口,因为在监听过程中若不做任何处理只要列表滑动便会进行监听,小菜的解决的方式有两种;

  1. 监听滑动到底部再进行业务操作调用接口,如问题一中的判断;
bool dataNotification(ScrollNotification notification) {  if (notification is ScrollEndNotification) {    //下滑到最底部    if (notification.metrics.extentAfter == 0.0) {      print('======下滑到最底部======');      loadData();    }  }  return true;}
  1. 尝试使用 ,对滑动进行监听,这个类可用于同步两个或更多个共享单个 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
{ var lastFileID = '0'; var rowNumber = 0; var cid = '29338'; var newsListBean = null; List
dataItems =
[]; @override void initState() { super.initState(); loadData(); } // 请求首页数据 Future
loadData() { this.isLoading = true; final Completer
completer = new Completer
(); 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:
[ 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:
[ 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 时间不长,还有很多不清楚和不理解的地方,如果又不对的地方还希望多多指出。

转载地址:http://dpfga.baihongyu.com/

你可能感兴趣的文章
Nginx限制带宽
查看>>
All Web Application Attack Techniques
查看>>
归档日志ORA-19809: 超出了恢复文件数的限制
查看>>
精品德国软件 UltraShredder 文件粉碎机
查看>>
PANDAS 数据合并与重塑(join/merge篇)
查看>>
文件时间信息在测试中的应用
查看>>
直播疑难杂症排查(8)— 播放杂音、噪音、回声问题
查看>>
如何写gdb命令脚本
查看>>
Android ListView展示不同的布局
查看>>
iOS宏(自己使用,持续更新)
查看>>
手把手玩转win8开发系列课程(3)
查看>>
NGINX引入线程池 性能提升9倍
查看>>
《淘宝技术这十年》读书笔记 (四). 分布式时代和中间件
查看>>
linux下mongodb定时备份指定的集合
查看>>
oVirt JBAS server start failed, ajp proxy cann't server correct. ovirt-engine URL cann't open
查看>>
CDP WebConsole上线公告
查看>>
ubuntu下安装摄像头应用程序xawtv
查看>>
PostgreSQL 如何比较两个表的定义是否一致
查看>>
Ambari安装Hadoop集群
查看>>
WCF学习之旅—基于ServiceDebug的异常处理(十七)
查看>>