Flutter学习笔记(25)--ListView实现上拉刷新下拉加载
如需转载,请注明出处:Flutter学习笔记(25)--ListView实现上拉刷新下拉加载
前面我们有写过ListView的使用:Flutter学习笔记(12)--列表组件,当列表的数据非常多时,需要使用长列表,比如淘宝后台的订单列表,手机通讯录等,这些列表项数据很多,长列表也是使用ListView作为基础组件,只不过需要添加一个列表项构造器itemBuilder。Flutter的长列表组件其实相当于Android中的RecyclerView,它会自动为您回收列表元素。在创建ListView.builder时,需要传入两个参数,一个列表的初始长度,一个itemBuilder函数。ListVIew还支持基于Sliver的延迟构建模型。
基于Sliver的延迟构建模式:
通常可滚动组件的子组件可能会非常多,占用的总高度也会非常大,如果要一次性将子组件全部构建出将会导致性能差的问题出现,为此,Flutter中提出一个Sliver(中文为"薄片"的意思)概念,如果一个可滚动组件支持Sliver模型,那么该滚动组件可以将子组件分成好多个薄片(Sliver),只有当Sliver出现在视口时才会去构建它,这种模型也成为"基于Sliver的延迟构建模型"。可滚动组件中有很多都支持基于Sliver的延迟构建模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView
使用ListVIew.separated给列表项之间添加一个分割组件
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatelessWidget {
//初始化数据源
final List<String> items = new List<String>.generate(, (i)=>"Item $i");
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'SingleChildScrollView Demo',
home: new Scaffold(
appBar: AppBar(
title: new Text('SingleChildScrollView Demo'),
),
body:new ListView.separated(
//列表滑动到边界时,显示iOS的弹出效果
physics: BouncingScrollPhysics(),
itemCount: items.length,
//列表项构造器
itemBuilder: (context,index){
return ListTile(title: new Text('${items[index]}'),);
},
//分割构造器
separatorBuilder: (context,index){
//分割组件
return new Divider(color: Colors.blue,);
},
),
),
);
}
}

下拉刷新
Flutter给我们提供了下拉刷新功能RefreshIndicator的组件,先整体说明一下下面Demo的代码逻辑,其实很简单,body返回一个RefreshIndicator组件,在该组件内的子组件是一个ListView,重点说一下RefreshIndicator的下拉回调方法onRefresh,在回调方法内延迟2秒中后将list内容清空,并且重新给list列表添加新的数据。
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _DemoAppState();
}
}
class _DemoAppState extends State<DemoApp> {
var _items = new List<String>();
@override
void initState() {
super.initState();
getData();
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'ListView Demo',
home: new Scaffold(
appBar: new AppBar(
title: new Text('ListView Demo'),
),
body: new RefreshIndicator(
onRefresh: _onRefresh,
child: new ListView.separated(
physics: BouncingScrollPhysics(),
itemBuilder: (context,index){
return ListTile(title:new Text('${_items[index]}'));
},
//分割线构造器
separatorBuilder: (context,index){
return new Divider(color: Colors.blue,);
},
//_items.length + 1是为了给最后一行的加载loading留出位置
itemCount: _items.length
),
),
),
);
}
void getData() {
//初始数据源
for (int i=;i<;i++){
_items.insert(_items.length, "第${_items.length}条原始数据");
print(_items[i]);
}
}
Future<void> _onRefresh() async {
await Future.delayed(Duration(seconds: )).then((e){
setState(() {
_items.clear();
for (int i=;i<;i++){
_items.insert(_items.length, "第${_items.length}条下拉刷新后的数据");
}
});
});
}
@override
void dispose() {
super.dispose();
}
}
这里需要注意的是,onRefresh回调方法要增加async....await,不然会出现下拉刷新的loading不会消失的问题:
Future<void> _onRefresh() async {
await Future.delayed(Duration(seconds: )).then((e){
setState(() {
_items.clear();
for (int i=;i<;i++){
_items.insert(_items.length, "第${_items.length}条下拉刷新后的数据");
}
});
});
}

上拉加载
先缕一下实现的思路,我们想要实现的效果是每页20条内容,共5页的内容,1-4页末尾数据后要展示加载新数据的loading,到第5页末尾数据展示“我是有底线的”,因此,我们的itemCount就要是itemCount: _items.length + 1.而不是itemCount: _items.length + ,这是因为要在最后留出来loading的位置,接下来就是要处理构建LisvtView里面的每一条item,如果当前item的索引是列表数据的最后一条数据,并且不是最后一页的话,展示loading,如果当前item的索引是列表数据的最后一条数据,并且是最后一页的话,展示“我是有底线的”,如果当前item的索引不是列表数据的最后一条,则展示下一条数据的内容。最后要处理的就是当页面滑动到最后了,要怎么获取新的数据。前面我们在写页面滑动的部分有讲到过controller属性(此属性接收一个ScrollController对象,ScrollController的主要作用是控制滚动位置和监听滚动事件),我们现在需要做的就是通过ListView的controller控制器来判断页面是否滑动到了最底部,如果滑动到了最底部,则获取新的数据并插入到list里面,最后通过setState通知页面重新构建。
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _DemoAppState();
}
}
class _DemoAppState extends State<DemoApp> {
ScrollController _controller = new ScrollController();
var _items = new List<String>();
var _mPage = ;
@override
void initState() {
super.initState();
getData();
//给_controller添加监听
_controller.addListener((){
//判断是否滑动到了页面的最底部
if(_controller.position.pixels == _controller.position.maxScrollExtent){
//如果不是最后一页数据,则生成新的数据添加到list里面
if(_mPage < ){
_retrieveData();
}
}
});
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'ListView Demo',
home: new Scaffold(
appBar: new AppBar(
title: new Text('ListView Demo'),
),
body: new RefreshIndicator(
onRefresh: _onRefresh,
child: new ListView.separated(
controller: _controller,
physics: BouncingScrollPhysics(),
itemBuilder: (context,index){
//判断是否构建到了最后一条item
if(index == _items.length){
//判断是不是最后一页
if(_mPage < ){
//不是最后一页,返回一个loading窗
return new Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
}else{
//是最后一页,显示我是有底线的
return new Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: new Text('我是有底线的!!!',style:TextStyle(color: Colors.blue),),
);
}
}else{
return ListTile(title:new Text('${_items[index]}'));
}
},
//分割线构造器
separatorBuilder: (context,index){
return new Divider(color: Colors.blue,);
},
//_items.length + 1是为了给最后一行的加载loading留出位置
itemCount: _items.length +
),
),
),
);
}
void getData() {
//初始数据源
for (int i=;i<;i++){
_items.insert(_items.length, "第${_items.length}条原始数据");
print(_items[i]);
}
}
void _retrieveData() {
//上拉加载新的数据
_mPage++;
Future.delayed(Duration(seconds: )).then((e){
for (int i=;i<;i++){
_items.insert(_items.length, "这是新加载的第${_items.length}条数据");
}
setState(() {
});
});
}
Future<void> _onRefresh() async {
await Future.delayed(Duration(seconds: )).then((e){
setState(() {
_mPage = ;
_items.clear();
for (int i=;i<;i++){
_items.insert(_items.length, "第${_items.length}条下拉刷新后的数据");
}
});
});
}
@override
void dispose() {
//移除监听,防止内存泄漏
_controller.dispose();
super.dispose();
}
}

以上就是今天下拉刷新和上拉加载的全部内容了,如果有错误的地方或者有任何疑问,欢迎留言!!!
Flutter学习笔记(25)--ListView实现上拉刷新下拉加载的更多相关文章
- ListView上拉刷新和分页加载完整的Dome
很多人工作的过程中都会碰到ListView下拉刷新和分页加载,然后大多数公司都已经把框架写好了,大家直接用就可以了,有些人一直对这个事情处于迷茫状态,为了让大家对上拉刷新和分页加载有一个比较全面的认识 ...
- Android之 RecyclerView,CardView 详解和相对应的上拉刷新下拉加载
随着 Google 推出了全新的设计语言 Material Design,还迎来了新的 Android 支持库 v7,其中就包含了 Material Design 设计语言中关于 Card 卡片概念的 ...
- jQuery模拟原生态App上拉刷新下拉加载
jQuery模拟原生态App上拉刷新下拉加载效果代码,鼠标上拉时会显示loading字样,并且会模拟加载一条静态数据,支持触屏设备使用. <!doctype html> <html ...
- 微信小程序 上拉刷新/下拉加载
小程序项目中上拉刷新下拉加载是比较常见的需求,官方文档也提供了相当友好的API,但是因为API隐藏的比较深,文档描述也比较模糊所以也折腾了一番(官方文档),在此记录一下使用方式 onPullDownR ...
- jQuery WeUI 组件下拉刷新和滚动加载的实现
最近在做手机版使用到了下拉刷新和滚动加载,记录一下实现过程: 一.引入文件 ? 1 2 3 4 <link rel="stylesheet" href="Conte ...
- 实现app上对csdn的文章列表上拉刷新下拉加载以及加入缓存文章列表的功能 (制作csdn app 四)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23698511 今天继续对我们的csdn客户端未完成的功能进行实现,本篇博客接着客 ...
- XRecyclerView上拉刷新下拉加载
效果图: 首先要添加依赖: //xrecyclerviewimplementation 'com.jcodecraeer:xrecyclerview:1.3.2'//Gsonimplementatio ...
- iOS:延迟加载和上拉刷新/下拉加载的实现
lazy懒加载(延迟加载)UITableView 举个例子,当我们在用网易新闻App时,看着那么多的新闻,并不是所有的都是我们感兴趣的,有的时候我们只是很快的滑过,想要快速的略过不喜欢的内容,但是只要 ...
- listView上拉刷新下拉加载
xlistview_header.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLa ...
随机推荐
- 小白学python-day01-电脑结构知识
作为一个”0“基础的经济学学士来说,专业分类选择了经统,多多少少和计算机有点关系,从今天开始学习python. 但行努力,莫问前程. day01学习电脑结构等知识. 因为这些知识是 有规则的,客观的文 ...
- Python基础之str常用方法、for循环
初学python,有些地方可能还不够明白,希望各位看官发现我的错误后留言指正! 一.字符串的索引与切片 注:字符串的第一位的索引值是0 1.索引案例 s = 'abcd' s1 = s[0] prin ...
- 记一次远程CMD开发过程
开发初衷: 有些同学电脑老是要出问题,但又不是什么大问题,通常几句cmd就能搞定.之前解决方案有2:一是远程演示,我口述别人操作:一是我写个cmd脚本,但毕竟不在本机不好调试.(吐槽一下常用的远程控制 ...
- 完整使用JDBC访问数据库
Connection con = null; PreparedStatement statement = null; ResultSet res = null; List<Student> ...
- SpringBoot的yml配置
Spring Boot的yml配置 #开发配置 spring: data: solr: host: http://localhost:6789/solr/mote mvc: view: # 页面默认前 ...
- H3C模拟器实验之网络地址转换
网络拓扑图 NOTE:各个设备的基本配置在拓扑图上已经标明(需要注意的是RTB的出接口也需要配置IP,但是使用ping -a 10.1.1.1 202.117.144.1 ping不通,这点不是很理解 ...
- mysql是如何实现事务隔离以及MVCC详解
提到事务,你肯定会想到ACID(Atomicity.Consistency.Isolation.Durability,即原子性.一致性.隔离性.持久性),我们就来说说其中I,也就是"隔离性& ...
- Mysql无法启动情况下,如何恢复数据?
本文适用于,mysql无法启动,但数据文件未丢失的情况. Mysql因意外情况,导致无法启动,数据库未做备份的情况下,如何将数据迁移至其他数据库中. 原数据库地址:192.168.1.100(以下简称 ...
- js 共有和私有
//共有 var SunHang = function(){ var name = "ssss"; this.name = "hhhhh"; function ...
- 每天用SpringBoot,还不懂RESTful API返回统一数据格式是怎么实现的?
上一篇文章RESTful API 返回统一JSON数据格式 说明了 RESTful API 统一返回数据格式问题,这是请求一切正常的情形,这篇文章将说明如何统一处理异常,以及其背后的实现原理,老套路, ...