Flutter开发之ListView下拉刷新上拉加载更多(35)
在Flutter开发之ListView组件(21) 文章中,我们了解了ListView组件的基本使用。但是数据比较少,没有涉及分页加载。而实际开发中,下拉刷新和分页加载几乎是所有APP的标配。在iOS 开发中我们通过MJRefresh 给UITableView添加mj_header和mj_footer刷新事件来触发下拉刷新和分页加载实现的。那么我们看一下Flutter中的下拉刷新跟上拉加载更多是如何实现的尼?
1. ListView组件
首先创建一个不带RefreshIndicator
ListView组件。就像之前的一样。
基础代码
import 'package:flutter/material.dart';
import 'package:hello/Models/Todo.dart';
import 'package:hello/Moudles/DetailScreen.dart';class ListViewRefreshTest extends StatefulWidget {@overridecreateState()=> _ListViewRefreshState();
}Widget _listViewWidget (BuildContext context, List<Todo> sourceList) {if(sourceList.length==0) {return null;} else {return ListView.builder(itemCount: sourceList.length,//设置physics属性总是可滚动physics: AlwaysScrollableScrollPhysics(),itemBuilder: (context,index) {return ListTile(title: Text(sourceList[index].title,style: TextStyle(fontSize: 22),),subtitle: Text(sourceList[index].description,style: TextStyle(fontSize: 18)),onTap: () {Navigator.push(context,MaterialPageRoute(builder:(context)=> DetailScreen(todo: sourceList[index]),));},);});}
}List<Todo> _myDataList(){return List.generate(20,(i) => new Todo('我是表第 $i 项','我是内容 $i',));
}class _ListViewRefreshState extends State<ListViewRefreshTest> {List<Todo> entityList = _myDataList();@overrideWidget build(BuildContext context) {// TODO: implement buildreturn new Scaffold(appBar: AppBar(title: Text('刷新和分页加载'),),body: _listViewWidget(context,entityList,),);}
}
下拉刷新
在Flutter中是通过RefreshIndicator
组件来完成下拉刷新的监听动作的。它跟原生Android中的SwipeRefreshLayout
设计思路一样,而且t在外观上几乎也一样,都是为了简化完成下拉刷新的监听动作。Google 发布的Material Design
语言更像是一套界面设计标准。
class RefreshIndicator extends StatefulWidget {/// Creates a refresh indicator.////// The [onRefresh], [child], and [notificationPredicate] arguments must be/// non-null. The default/// [displacement] is 40.0 logical pixels.////// The [semanticsLabel] is used to specify an accessibility label for this widget./// If it is null, it will be defaulted to [MaterialLocalizations.refreshIndicatorSemanticLabel]./// An empty string may be passed to avoid having anything read by screen reading software./// The [semanticsValue] may be used to specify progress on the widget.const RefreshIndicator({Key key,@required this.child,this.displacement = 40.0,@required this.onRefresh,this.color,this.backgroundColor,this.notificationPredicate = defaultScrollNotificationPredicate,this.semanticsLabel,this.semanticsValue,}) : assert(child != null),assert(onRefresh != null),assert(notificationPredicate != null),super(key: key);/// The widget below this widget in the tree.////// The refresh indicator will be stacked on top of this child. The indicator/// will appear when child's Scrollable descendant is over-scrolled.////// Typically a [ListView] or [CustomScrollView].
上面的构造方法中必要参数的注释说明,光说不如直接实战来的直接。我们在 1.中的代码基础上添加 RefreshIndicator
组件来完成下拉刷新的功能。我们只需要3步:
RefreshIndicator
来warpperListView
- 实现
onRefresh
并在方法中更新数据源
增加代码片段
// 下拉刷新Future<Null> _handleRefresh() async {print('-------开始刷新------------');await Future.delayed(Duration(seconds: 2), () { //模拟延时setState(() {entityList.clear();entityList = List.generate(10,(i) => new Todo("刷新我是表第 $i 项",'刷新我是内容 $i'));return null;});});}
修改代码片段
body: RefreshIndicator(child: _listViewWidget(context,entityList),onRefresh: _handleRefresh),
效果如图:
上拉加载更多
刷新完成了,接下来我们实现分页加载。我们借助ScrollController给ListView添加滑动监听事件。也需要两步:
- 增加两个变量:
ScrollController
和isLoadData
- 实现
_scrollController.addListener
并在方法中更新数据源
新增代码片段
ScrollController _scrollController = new ScrollController();
bool isLoadData = false;@overridevoid initState() {super.initState();print('你好!');_scrollController.addListener((){if (_scrollController.position.pixels ==_scrollController.position.maxScrollExtent) {print("------------加载更多-------------");_getMoreData();callTimes = callTimes+1}});}
Future<Null> _getMoreData() async {await Future.delayed(Duration(seconds: 2), () { //模拟延时操作if (!isLoadData) {isLoadData = true;setState(() {isLoadData = false;List<Todo> newList = List.generate(5,(i) => Todo('分页--我是表第 ${i + entityList.length} 项','刷新我是内容 ${i + entityList.length} '));entityList.addAll(newList);});}});}
完整代码如下:
import 'package:flutter/material.dart';
import 'package:hello/Models/Todo.dart';
import 'package:hello/Moudles/DetailScreen.dart';class ListViewRefreshTest extends StatefulWidget {@overridecreateState()=> _ListViewRefreshState();
}class LoadMoreView extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(child: Padding(padding: const EdgeInsets.all(18.0),child: Center(child: Row(children: <Widget>[CircularProgressIndicator(),Padding(padding: EdgeInsets.all(10)),Text('加载中...')],mainAxisAlignment: MainAxisAlignment.center,),),), color: Colors.white70,);}
}Widget _listViewWidget (BuildContext context, List<Todo> sourceList,ScrollController scrollController,bool isNeedLoad) {if(sourceList.length==0) {return null;} else {return ListView.builder(itemCount: isNeedLoad? sourceList.length+1 : sourceList.length,//设置physics属性总是可滚动physics: AlwaysScrollableScrollPhysics(),itemBuilder: (context,index) {if (index == sourceList.length) {return LoadMoreView();} else {return ListTile(title: Text(sourceList[index].title,style: TextStyle(fontSize: 22),),subtitle: Text(sourceList[index].description,style: TextStyle(fontSize: 18)),onTap: () {Navigator.push(context,MaterialPageRoute(builder:(context)=> DetailScreen(todo: sourceList[index]),));},);}},controller: scrollController,);}
}List<Todo> _myDataList(){return List.generate(10,(i) => new Todo('我是表第 $i 项','我是内容 $i',));
}int callTimes = 0;
class _ListViewRefreshState extends State<ListViewRefreshTest> {List<Todo> entityList = _myDataList();ScrollController _scrollController = new ScrollController();bool isLoadData = false;@overridevoid initState() {super.initState();print('你好!');_scrollController.addListener((){if (_scrollController.position.maxScrollExtent == _scrollController.position.pixels) {print("------------加载更多-------------");_getMoreData();}});}// 下拉刷新Future<Null> _handleRefresh() async {print('-------开始刷新------------');await Future.delayed(Duration(seconds: 2), () { //模拟延时setState(() {entityList.clear();entityList = List.generate(10,(i) => new Todo("刷新我是表第 $i 项",'刷新我是内容 $i'));return null;});});}Future<Null> _getMoreData() async {await Future.delayed(Duration(seconds: 2), () { //模拟延时操作if (!isLoadData) {isLoadData = true;setState(() {isLoadData = false;List<Todo> newList = List.generate(5,(i) => Todo('分页--我是表第 ${i + entityList.length} 项','刷新我是内容 ${i + entityList.length} '));entityList.addAll(newList);});}});}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn new Scaffold(appBar: AppBar(title: Text('刷新和分页加载'),),body: RefreshIndicator(onRefresh: _handleRefresh,child: _listViewWidget(context,entityList,_scrollController,isLoadData),),);}
}
整体效果图如下:
遇到问题
- 问题:使用ListView.builder做个简单的下拉刷新,发现数据不满一屏,无法滑动。
解决方法:增加physics: AlwaysScrollableScrollPhysics(),
即可
ListView.builder(
//设置physics属性总是可滚动
physics: AlwaysScrollableScrollPhysics(),
)
- 问题:数据不满一屏,上拉分页加载,无法触发_scrollController.addListener();
暂时解决:
body修改
body:new NotificationListener(onNotification: _onNotification,child: RefreshIndicator(onRefresh: _handleRefresh,child: _listViewWidget(context,entityList,_scrollController,isLoadData),),),
);
添加监听通知的方法
int callTimes = 0;
class _ListViewRefreshState extends State<ListViewRefreshTest> {List<Todo> entityList = _myDataList();ScrollController _scrollController = new ScrollController();bool isLoadData = false;double offset = 0;// 为了解决不满一屏无法上拉加载分页的问题。bool _onNotification(ScrollNotification notification) {if (notification is! ScrollNotification) {// 如果不是滚动事件,直接返回return false;}if (notification is OverscrollNotification) {offset = notification.overscroll>offset ? notification.overscroll:offset;}print('hdhhd---$offset');if (notification is ScrollEndNotification) {// 要加上不满一屏幕的条件判断,直执行一次,待到列表数据内容超过屏幕高度,不再这里指执行了。走_scrollController.addListener来分页if(offset>15&&callTimes==0) {callTimes = callTimes + 1;_getMoreData();offset = 0;}}return true;}
Flutter开发之ListView下拉刷新上拉加载更多(35)相关推荐
- uni-app下拉刷新触底加载更多
首先在pages.json 配置文件中配置 "enablePullDownRefresh": true 需要在哪用加载就配置在路由的style里 两个事件 //下拉刷新 o ...
- Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表
本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...
- recyclerview的数据刷新(下拉刷新和自动加载更多)以及添加提示语(例如:“数据已加载完毕”)
下拉加载更多的核心是SwipeRefreshLayout搭配Recyclerview进行使用.布局为 <android.support.v4.widget.SwipeRefreshLayout ...
- Flutter开发之ListView使用第三方pull_to_refresh加载更多(36)
在Flutter开发之ListView下拉刷新&上拉加载更多(35) 中我们实现了下拉刷新.上拉分页加载的功能.但是使用起来非常不方便,且不满一屏时难以处理. 今天介绍ListView使用第三 ...
- 开启Fluter基础之旅五-------ListView 3D滚动、Flipper效果、ListView下拉刷新上拉加载、ListView重排序...
继续来来操练Flutter的基础,对于Flutter的学习也有一段时间了,实操项目还木有做过,所以待这次基础学完之后就打算用一个项目对之前所学的进行一下巩固,不然光学这些零散的知识点最终还是不会Flu ...
- 分享轮子-flutter下拉刷新上拉加载
flutter下拉上拉组件轮子 什么是flutter? 首先说下flutter,估计这个应该挺多人没听过flutter这个框架,它是一个google推出的跨平台的移动应用UI框架,和React Nat ...
- Android滑动冲突解决方式(下拉刷新上拉加载更多,适配RecyclerView/ListView/ScrollView)
一.Android事件的分发机制 这里需要了解下Andorid事件的分发机制.事件分发一般是针对一组事件,即ACTION_DOWN > ACTION_UP 或 ACTION_DOWN > ...
- react-native ListView 封装 实现 下拉刷新/上拉加载更多
1.PageListView 组件封装 src/components/PageListView/index.js /*** 上拉刷新/下拉加载更多 组件*/ import React, { Compo ...
- android listview下拉刷新动画,android 安卓 listview 支持下拉刷新 上拉加载更多
[1]重写listViewimport java.text.SimpleDateFormat; import java.util.Date; import com.example.testdddlea ...
最新文章
- Linux网络编程实例分析
- html在线缓存视频,javascript – 如何为HTML视频添加缓冲
- 2021 GitHub年度报告:7300万开发者,最爱的依旧是Javascript
- MySql报2006error错误的解决方法(数据过大)
- poj 3692(二分图匹配--最大独立集)
- 为CentOS 7安装VMware-tools
- 一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权
- 未能连接到许可证服务器 发生错误 -96,ug启动许可证错误怎么办 UG软件启动许可证错误96解决方法...
- 如何设计一个安全的对外接口,老司机总结了这几点...
- IDEA 创建git 分支 拉取分支
- python代码写好了怎么运行-python代码是怎样运行的
- matlab细胞数组类型建立及操作
- Android Jni开发-实战篇(CMake)
- 漏洞复现|Microsoft Office数学公式编辑器内存损坏漏洞(CVE-2017-11882 )
- windows下采用批处理命令实现 FTP文件夹下载 包含子文件夹下载 Bat
- Office 2007卸载
- Python Tic Tac Toe游戏
- android应用是非正式版本,Androidstudio 打包apk安装失败 应用是非正式发布版本,当前设备不支持安装...
- 图片按日期批量导入WPS表格
- java项目_第171期ssm房屋租赁系统_计算机毕业设计