Flutter ListView 下拉刷新,上拉加载更多
时间:2022-07-24
本文章向大家介绍Flutter ListView 下拉刷新,上拉加载更多,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
正常项目中使用ListView一定会涉及到分页加载的问题,此时无法避免地需要用到下拉刷新和上拉加载更多的功能。
本文就当前知识面对这两个知识点做简单的实际demo介绍。
本文“下拉刷新,上拉加载”效果图:
1、上拉加载更多
完整代码:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
class RefreshListViewDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return RefreshListViewDemoState();
}
}
class RefreshListViewDemoState extends State<RefreshListViewDemo> {
static const loadingTag = "##loading##"; //表尾标记
var _words = <String>[loadingTag];
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("ListView下拉刷新,上拉加载更多"),
),
body: Stack(
children: <Widget>[
ListView.separated(
itemBuilder: (context, index) {
if (_words[index] == loadingTag) {
if (_words.length - 1 < 100) {
//获取数据
_retrieveData();
//加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0)),
);
} else {
//已经加载了100条数据,不再获取数据。
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text(
"没有更多了",
style: TextStyle(color: Colors.grey),
));
}
}
//显示单词列表项
return ListTile(title: Text(_words[index]));
},
separatorBuilder: (context, index) => Divider(height: .0),
itemCount: _words.length),
],
));
}
void _retrieveData() {
Future.delayed(Duration(seconds: 2)).then((e) {
_words.insertAll(
_words.length - 1,
//每次生成20个单词
generateWordPairs().take(20).map((e) => e.asPascalCase).toList());
setState(() {
//重新构建列表
});
});
}
}
void main() {
runApp(new MaterialApp(
title: "ListView下拉刷新,上拉加载更多",
theme: ThemeData(primaryColor: Colors.deepOrangeAccent),
home: RefreshListViewDemo(),
));
}
关键步骤分解:
- 先准备一个存放数据的String数组,设置一个结束标记到数组中。此标记始终在列表数据的末尾,是判断列表滑动是否到达尾部的标记。 static const loadingTag = "##loading##"; //表尾标记 var _words = <String>[loadingTag];
- 准备一个模拟网络请求下载数据的方法。 void _retrieveData() { Future.delayed(Duration(seconds: 2)).then((e) {//模拟2秒网络请求 _words.insertAll( //将数据插入到倒数第二个item的位置,因为最后一个是结束标记。 _words.length - 1, //每次生成20个单词 generateWordPairs().take(20).map((e) => e.asPascalCase).toList()); setState(() { //重新构建列表 }); }); }
- 根据条件展示
上拉加载更多
。 3.1. 当监测到最后一条数据,又满足在100条数据以下,显示loading动画布局,并去网络获取数据,获取到数据之后插入到结束标记之前。超过100条数据,显示没有更多了
。 3.2. 如果不是最后一条数据,就正常展示该项的内容(随机英文单词)。 if (_words[index] == loadingTag) { if (_words.length - 1 < 100) { //获取数据 _retrieveData(); //加载时显示loading return Container(……); } else { //已经加载了100条数据,不再获取数据。 return Container( …… child: Text( "没有更多了", style: TextStyle(color: Colors.grey), )); } } //显示单词列表项 return ListTile(title: Text(_words[index]));
2、下拉刷新(包含上拉加载)
下拉刷新可以有很多种实现,这里只介绍如何使用原生下拉刷新控件。
完整代码:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
class RefreshListViewDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return RefreshListViewDemoState();
}
}
class RefreshListViewDemoState extends State<RefreshListViewDemo> {
static const loadingTag = "##loading##"; //表尾标记
var _words = <String>[loadingTag];
bool showRefreshLoad = false; //控制何时展示下拉刷新loading
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("ListView下拉刷新,上拉加载更多"),
),
body: RefreshIndicator(
onRefresh: _toRefresh,
child: ListView.separated(
itemBuilder: (context, index) {
if (_words[index] == loadingTag) {
if (_words.length - 1 < 100) {
//获取数据
_retrieveData();
//加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0)),
);
} else {
//已经加载了100条数据,不再获取数据。
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text(
"没有更多了",
style: TextStyle(color: Colors.grey),
));
}
}
//显示单词列表项
return ListTile(title: Text(_words[index]));
},
separatorBuilder: (context, index) => Divider(height: .0),
itemCount: _words.length,
),
));
}
void _retrieveData() {
Future.delayed(Duration(seconds: 10)).then((e) {
_words.insertAll(
_words.length - 1,
//每次生成20个单词
generateWordPairs().take(15).map((e) => e.asPascalCase).toList());
setState(() {
//重新构建列表
});
});
}
Future _toRefresh() async {
// 延迟3秒后添加新数据, 模拟网络加载
await Future.delayed(Duration(seconds: 2), () {
setState(() {
_words.clear();
_words.addAll(
//每次生成20个单词
generateWordPairs().take(15).map((e) => e.asPascalCase).toList());
_words.add(loadingTag); //最后加上结束标记
});
});
}
}
void main() {
runApp(new MaterialApp(
title: "ListView下拉刷新,上拉加载更多",
theme: ThemeData(primaryColor: Colors.deepOrangeAccent),
home: RefreshListViewDemo(),
));
}
关键步骤分解:
- 使用
RefreshIndicator
,包裹ListView
。 body: RefreshIndicator( onRefresh: _toRefresh, child: ListView.separated( - 在
onRefresh
里传入_toRefresh
方法做网络请求(此处模拟网络)。
此处使用english_words
库进行内容生成。
Future _toRefresh() async {
// 延迟3秒后添加新数据, 模拟网络加载
await Future.delayed(Duration(seconds: 2), () {
setState(() {
_words.clear();
_words.addAll(
//每次生成20个单词
generateWordPairs().take(15).map((e) => e.asPascalCase).toList());
_words.add(loadingTag); //最后加上结束标记
});
});
}
完成之后就实现了整个下拉刷新步骤。
效果图见本文开篇处。
注意:有些朋友在使用generateWordPairs()的时候可能会遇到找不到该方法的问题(我就遇到了)。事实上这是一个自动生成英文单词的第三方库。需要导入english_words库才能使用该方法。
具导入方法体在我Flutter系列文章中的《Flutter问题:import 'package:english_words/english_words.dart'失败》一文中有详细步骤。
- 连AI都在看《英雄联盟》游戏直播
- MAC使用adb工具
- 并发编程之master-worker模式
- Android WebView全面总结
- Url参数中出现+、空格、=、%、&、#等字符的解决办法
- 解决CSS垂直居中的几种方法(基于绝对定位,基于视口单位,Flexbox方法)
- Go语言学习之cgo(golang与C语言相互调用)
- golang之旅--数据类型之字符串
- Android保存图片到系统图库
- 基于Vue.js的大型报告页项目实现过程及问题总结(二)
- 使用Hexo搭建专属Blog
- Android项目中文字乱码问题
- golang中发送http请求的几种常见情况
- 注册中心 Eureka 源码解析 —— Eureka-Server 启动(一)之 ServerConfig
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 独家 | 教你用Python来计算偏差-方差权衡
- 使用 KinD 加速 CI/CD 流水线
- 使用 Docker 加速开发工作流
- Kubernetes CRD 自定义控制器
- 推荐算法之: LFM 推荐算法
- 推荐算法之: DeepFM及使用DeepCTR测试
- Cypress系列(61)- 断言最佳实践
- Cypress系列(62)- 改造 PageObject 模式
- CPU 执行程序的秘密,藏在了这 15 张图里
- Cypress系列(63)- 使用 Custom Commands
- Python字符串操作大全
- Cypress系列(64)- 数据驱动策略
- 别只会搜日志了,求你懂点原理吧
- Cypress系列(65)- 测试运行失败自动重试
- CentOS7下编译FFMPEG源代码