在《APP 开发从 0 到 1(三)布局与 ListView》我们完成了 ListView,这篇文章将做 ListView 下拉加载和加载更多。

ListView 下拉加载

Flutter 提供了 RefreshIndicator 下拉刷新组件,可以轻松让我们实现 Material Design 风格的下拉刷新效果。

参数详解

//下拉刷新组件const RefreshIndicator({Key key,@required this.child,this.displacement: 40.0, //触发下拉刷新的距离@required this.onRefresh, //下拉回调方法,方法需要有async和await关键字,没有await,刷新图标立马消失,没有async,刷新图标不会消失this.color, //进度指示器前景色,默认为系统主题色this.backgroundColor, //背景色this.notificationPredicate: defaultScrollNotificationPredicate,})

效果预览

完整代码

废话不多说,直接上完整代码,你可细品下哦。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';class ListViewPage extends StatefulWidget {@overrideListViewPageState createState() => new ListViewPageState();
}class ListViewPageState extends State<ListViewPage> {List list = new List(); //列表要展示的数据@overridevoid initState() {super.initState();getData();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('AndBlog'),),body: RefreshIndicator(onRefresh: _onRefresh,child: ListView.builder(itemCount: list.length,itemBuilder: (BuildContext context, int index) {return ListTile(title: Text(list[index]),);},)),floatingActionButton: FloatingActionButton(tooltip: 'Increment',child: Icon(Icons.account_box),onPressed: () {print("FloatingActionButton");},elevation: 30,), // This trailing comma makes auto-formatting nicer for build methods.);}Future<Null> _onRefresh() async {await Future.delayed(Duration(seconds: 3), () {print('refresh');setState(() {list = List.generate(20, (i) => '哈喽,我是下拉刷新的数据 $i');});});}Future getData() async {await Future.delayed(Duration(seconds: 2), () {setState(() {list = List.generate(30, (i) => '哈喽,我是原始数据 $i');});});}
}

ListView 加载更多

Flutter 没有直接提供加载更多组件,但我们可以在 ListView 监听 ScrollController,判断是否滑到底,然后加载下一页。

效果预览

完整代码

import 'package:flutter/material.dart';
import 'package:flutter_andblog/andblog/common/color_common.dart';
import 'package:flutter_andblog/andblog/common/http_common.dart';
import 'package:flutter_andblog/andblog/detail/blog_detail_page.dart';
import 'package:http/http.dart' as http;
import 'blog.dart';class BlogListPage extends StatefulWidget {@overrideBlogListPageState createState() => new BlogListPageState();
}class BlogListPageState extends State<BlogListPage> {List<Blog> _blogList = [];String loadMoreText = "正在加载中...";TextStyle loadMoreTextStyle =new TextStyle(color: const Color(0xFF4483f6), fontSize: 14.0);ScrollController scrollController = new ScrollController();var hasData = true;var page = 0;@overridevoid initState() {super.initState();//一进页面就请求接口_getBlogListData();scrollController.addListener(() {if (scrollController.position.pixels ==scrollController.position.maxScrollExtent) {//已经滑到底了if (hasData) {//还有数据,加载下一页setState(() {loadMoreText = "正在加载中...";loadMoreTextStyle =new TextStyle(color: const Color(0xFF4483f6), fontSize: 14.0);});page++;print("page=" + page.toString());_getBlogListData();} else {setState(() {loadMoreText = "没有更多数据";loadMoreTextStyle =new TextStyle(color: const Color(0xFF999999), fontSize: 14.0);});}}});}@overridevoid dispose() {scrollController.dispose();super.dispose();}//网络请求Future _getBlogListData() async {//一页加载8条数据,skip为跳过的数据,比如加载第二页(page=1),skip跳过前8条数据,即显示第9-16条数据var skip = page * 8;print("blog_list_url=" + HttpCommon.blog_list_url + skip.toString());var response = await http.get(HttpCommon.blog_list_url + skip.toString(),headers: HttpCommon.headers());if (response.statusCode == 200) {// setState 相当于 runOnUiThreadsetState(() {var data = Blog.decodeData(response.body);if (data.length < 8) {//某页数据小于8,表明没有下一页了hasData = false;} else {hasData = true;}_blogList.addAll(data);print("_blogList.length0=" + _blogList.length.toString());});}}@overrideWidget build(BuildContext context) {var content;if (_blogList.length == 0) {content = new Center(// 可选参数 child:child: new CircularProgressIndicator(),);} else {content = _contentList();}return Scaffold(backgroundColor: ColorCommon.backgroundColor,appBar: AppBar(title: Text('AndBlog'),),body: content,floatingActionButton: FloatingActionButton(tooltip: 'Increment',child: Icon(Icons.account_box),onPressed: () {print("FloatingActionButton");},elevation: 30,), // This trailing comma makes auto-formatting nicer for build methods.);}Widget _contentList() {print("_blogList.length=" + _blogList.length.toString());return new RefreshIndicator(onRefresh: _onRefresh,child: ListView.builder(itemCount: _blogList.length + 1,itemBuilder: (BuildContext context, int index) {if (index == _blogList.length) {return _buildProgressMoreIndicator();} else {return _blogItem(index);}},controller: scrollController,));}Future<Null> _onRefresh() async {await Future.delayed(Duration(seconds: 1), () {print('refresh');setState(() {page = 0;_blogList.clear();_getBlogListData();});});}Widget _buildProgressMoreIndicator() {return new Padding(padding: const EdgeInsets.all(15.0),child: new Center(child: new Text(loadMoreText, style: loadMoreTextStyle),),);}Widget _blogItem(int index) {Blog blog = _blogList[index];var date = new Padding(padding: const EdgeInsets.only(top: 20.0,left: 10.0,right: 10.0,),child: new Text(blog.date,textAlign: TextAlign.center,style: TextStyle(color: ColorCommon.dateColor, fontSize: 18),));var cover = new Padding(padding: const EdgeInsets.only(top: 10.0,left: 10.0,right: 10.0,),child: new ClipRRect(borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0),topRight: Radius.circular(10.0)),child: new Image.network('http://pic1.win4000.com/wallpaper/2020-04-21/5e9e676001e20.jpg',)));var title = new Text(blog.title,style: TextStyle(color: ColorCommon.titleColor, fontSize: 22),);var summary = new Padding(padding: const EdgeInsets.only(top: 5.0,),child: new Text(blog.summary,textAlign: TextAlign.left,style: TextStyle(color: ColorCommon.summaryColor, fontSize: 18)));var titleSummary = new Container(padding: const EdgeInsets.all(10.0),alignment: Alignment.topLeft,decoration: new BoxDecoration(color: Colors.white,borderRadius: BorderRadius.only(bottomLeft: Radius.circular(10.0),bottomRight: Radius.circular(10.0)),shape: BoxShape.rectangle,),margin: const EdgeInsets.only(left: 10, right: 10.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,mainAxisSize: MainAxisSize.min,children: <Widget>[title, summary],),);var blogItem = new GestureDetector(//点击事件onTap: () => navigateToMovieDetailPage(blog.objectId, index),child: new Column(children: <Widget>[date,cover,titleSummary,],),);return blogItem;}// 跳转页面navigateToMovieDetailPage(String blogId, Object imageTag) {Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) {return new BlogDetailPage(blogId, imageTag: imageTag);}));}
}

listview 刷新结束 监听_Flutter 开发从 0 到 1(四)ListView 下拉加载和加载更多相关推荐

  1. android 下拉刷新监听,说说在 Android 的 RecyclerView 中如何实现下拉刷新

    1 SwipeRefreshLayout 修改布局文件,新增 SwipeRefreshLayout :<?xml  version="1.0" encoding=" ...

  2. Android 关于ListView中按钮监听的优化问题(方法二)

    关于ListView中按钮监听的优化问题(方法一)地址: http://www.cnblogs.com/steffen/p/3951901.html 之前的方法一,虽然能够解决position的传递, ...

  3. Android 集成高德地图——当前定位,添加图标,画路线,设置显示中心位置,比例,地图刷新位置监听,判断GPS开启,去打开GPS

    /*** 判断定位服务是否开启** @param* @return true 表示开启*/ public static boolean isLocationEnabled(Context contex ...

  4. html5监听动画结束,css3动画是否结束监听事件

    css3动画是否结束监听事件: var domObj = $("#id"); domObj [0].addEventListener("webkitAnimationEn ...

  5. avplayer播放结束监听

    //添加播放结束监听 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinishe ...

  6. Android开发笔记(一百二十三)下拉刷新布局SwipeRefreshLayout

    SwipeRefreshLayout 下拉刷新布局SwipeRefreshLayout是Android又一与时俱进的控件,顾名思义它随着用户手势向下滑动就会触发刷新操作.从实际的下拉效果来看,Swip ...

  7. ubuntu服务器上,求生之路2服务器如何把监听地址改为0.0.0.0

    今天准备尝试用rcon密码连接控制台的时候,出现了问题,由于游戏监听地址是127.0.1.1,导致无法远程连接,今天自己摸索了下解决了问题. 方法一:由于求生之路2服务器不属于内部自带的服务器,因此网 ...

  8. uniapp实现上拉刷新,下拉加载

    上拉刷新,下拉加载这个功能实际上在我们的应用当中使用范围是很广的,比如说商城中心在展示商品的时候就可以使用下拉加载这样的功能,那么如何实现呢? 首先遇到这个功能我就去搜插件市场了.经过我下载了不少的插 ...

  9. uniapp小程序如何通过虚拟列表配合节流,完成上拉刷新下拉加载,避免页面卡顿,提升性能呢?

    本文将介绍uniapp小程序中如何使用虚拟列表和节流两种技术实现上拉刷新下拉加载功能,同时避免因渲染大量数据导致的页面卡顿问题. 一.虚拟列表 在uniapp小程序开发中,当我们需要渲染大量列表数据时 ...

最新文章

  1. asp.net性能常用优化
  2. python课程怎么样-python课程体系是怎么样的?
  3. C/C++各种系统开发环境搭建
  4. python如何给一组数据打标签_给数据集打标签python代码实现(1)
  5. linux netperf的安装
  6. Perl中判断数组或hash为空
  7. uni-app 微信公众号支付
  8. word 中巧妙添加分隔线
  9. 尹伊:我的学习成长路径
  10. 面试官:Redis中哈希分布不均匀该怎么办
  11. Bootloader的启动与功能
  12. VMware 虚拟机启动时出现错误:The virtual machine appears to be in use
  13. T0001.数据结构面试题---栈---获取最小值
  14. 套料软件XSuperNEST产品及成功因素介绍
  15. 江西服装学院计算机考试是几级,江西服装学院2018年艺术类报考须知(江苏省)
  16. what is BI and OLAP?
  17. java计算机毕业设计Vue框架龙猫宠物交易平台MyBatis+系统+LW文档+源码+调试部署
  18. 购买云数据库与云服务器总结
  19. [附源码]Nodejs计算机毕业设计基于技术的高校学生勤工俭学管理系统的设计与开发Express(程序+LW)
  20. Linux操作系统安全

热门文章

  1. 芝麻HTTP: Python爬虫利器之PyQuery的用法
  2. Kubernetes插件部署
  3. 网络安全工作中最可怕的14种自己人
  4. 廖雪峰JS教程--条件判断
  5. Acey.ExcelX实例演练(1)—从GridView中导出Excel报表
  6. SCSM 2012 SP1创建SCOM连接器
  7. 将访问的文件夹变为磁盘盘符-摘自网络
  8. 批量杀死MySQL连接的几种方法
  9. windows7安装和问题排除,绝对有用!
  10. 袁桂英(帮别人名字作诗)