Dart4Flutter - 01 – 变量、类型和函数

Dart4Flutter – 02 –控制流 和异常

Dart4Flutter – 03 – 类和泛型

Dart4Flutter – 04 – 异步和库

Dart4Flutter - 拾遗01 - flutter-dart环境搭建

Dart4Flutter - 不可变性

Flutter入门 - 状态管理

Flutter 入门实例1

Flutter 入门 - Container 属性详解

Flutter 入门-本地访问-MethodChannel

Flutter 实例 - 加载更多的ListView

Flutter 实例 - 从本地到Flutter通信 - Event Channels

本教程完成一个有加载更多的ListView,最终效果如下图所示:

开始

首先我们只在列表中展示10个整数。

class MyHomePage extends StatefulWidget {@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i); // 产生数据@overridevoid initState() {super.initState();}@overridevoid dispose() {super.dispose();}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: new Text("Number $index"));},),);}
}
复制代码

动态添加数据

首先我们模拟一个http请求,假设我们通过传递from和to参数,然后返回他们之间的数。我们将添加延迟时间,这样看起来更像是网络加载。具体代码如下所示:

/// from - 包括, to - 不包括
/// 通过这个模拟http请求
Future<List<int>> fakeRequest(int from, int to) async {
// 如果对Future不熟悉,可以参考 https://juejin.im/post/5b2c67a351882574a756f2ebreturn Future.delayed(Duration(seconds: 2), () {return List.generate(to - from, (i) => i + from);});
}
复制代码

当用户将列表滚动到最底,我们将会调用上面的方法。为了监听列表是否已经滚动到最底,最简单的方式就是给列表添加一个ScrollController,当列表滚动的时候,就会发出一个请求。但是防止频繁的发送http请求,我们需要添加一个变量isPerformingRequest,表示是否有请求正在进行。只有当isPerformingRequest为false时,才能开始一个新的请求。

class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i);ScrollController _scrollController = new ScrollController();bool isPerformingRequest = false; // 是否有请求正在进行@overridevoid initState() {super.initState();_scrollController.addListener(() {if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {_getMoreData();}});}@overridevoid dispose() {_scrollController.dispose();super.dispose();}_getMoreData() async {if (!isPerformingRequest) { // 判断是否有请求正在执行setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length + 10);setState(() {items.addAll(newEntries);isPerformingRequest = false;// 下一个请求可以开始了});}}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(title: new Text("Number $index"));},controller: _scrollController,),);}
}
复制代码

如果你现在运行代码,你可以看数据可以动态的加载,但是这个距离我们最终想要的效果还有差距。我们需要添加一些提示,告知用户数据正在加载中。

进度提示

相关的组件是CircularProgressIndicator,他被Center、Opacity、Padding所包裹。我们将用Opacity组件控制CircularProgressIndicator的显示,当请求正在进行中时显示。整个组件的代码如下所示:

Widget _buildProgressIndicator() {return new Padding(padding: const EdgeInsets.all(8.0),child: new Center(child: new Opacity(opacity: isPerformingRequest ? 1.0 : 0.0,child: new CircularProgressIndicator(),),),);
}
复制代码

最后一件事是将这个组件添加到我们的ListView上:

@override
Widget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length + 1,itemBuilder: (context, index) {if (index == items.length) {return _buildProgressIndicator();} else {return ListTile(title: new Text("Number $index"));}},controller: _scrollController,),);
}
复制代码

最终效果如下:

处理空数据情况

下面是附加内容,处理当请求返回的数据为空时的晴空。我们通过ScrollControllerListView一些动画。

_getMoreData() async {if (!isPerformingRequest) {setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length); //returns empty listif (newEntries.isEmpty) {double edge = 50.0;double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;if (offsetFromBottom < edge) {_scrollController.animateTo(_scrollController.offset - (edge -offsetFromBottom),duration: new Duration(milliseconds: 500),curve: Curves.easeOut);}}setState(() {items.addAll(newEntries);isPerformingRequest = false;});}
}
复制代码

下面是完整的代码:

import 'dart:async';import 'package:flutter/material.dart';void main() => runApp(new MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(theme: new ThemeData(primarySwatch: Colors.blue),home: new MyHomePage(),);}
}class MyHomePage extends StatefulWidget {@override_MyHomePageState createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {List<int> items = List.generate(10, (i) => i);ScrollController _scrollController = new ScrollController();bool isPerformingRequest = false;@overridevoid initState() {super.initState();_scrollController.addListener(() {if (_scrollController.position.pixels ==_scrollController.position.maxScrollExtent) {_getMoreData();}});}@overridevoid dispose() {_scrollController.dispose();super.dispose();}_getMoreData() async {if (!isPerformingRequest) {setState(() => isPerformingRequest = true);List<int> newEntries = await fakeRequest(items.length, items.length + 10); //returns empty listif (newEntries.isEmpty) {double edge = 50.0;double offsetFromBottom = _scrollController.position.maxScrollExtent -_scrollController.position.pixels;if (offsetFromBottom < edge) {_scrollController.animateTo(_scrollController.offset - (edge - offsetFromBottom),duration: new Duration(milliseconds: 500),curve: Curves.easeOut);}}setState(() {items.addAll(newEntries);isPerformingRequest = false;});}}Widget _buildProgressIndicator() {return new Padding(padding: const EdgeInsets.all(8.0),child: new Center(child: new Opacity(opacity: isPerformingRequest ? 1.0 : 0.0,child: new CircularProgressIndicator(),),),);}@overrideWidget build(BuildContext context) {return new Scaffold(appBar: AppBar(title: Text("Infinite ListView"),),body: ListView.builder(itemCount: items.length + 1,itemBuilder: (context, index) {if (index == items.length) {return _buildProgressIndicator();} else {return ListTile(title: new Text("Number $index"));}},controller: _scrollController,),);}
}/// from - inclusive, to - exclusive
Future<List<int>> fakeRequest(int from, int to) async {return Future.delayed(Duration(seconds: 2), () {return List.generate(to - from, (i) => i + from);});
}
复制代码

有任何问题,欢迎大家提问

参考

  • marcinszalek.pl/flutter/inf…

Flutter 实例 - 加载更多的ListView相关推荐

  1. 一个到顶部自动加载更多的ListView

    为什么80%的码农都做不了架构师?>>>    一个可以到顶自动加载更多的ListView,实现该控件的目的是用于im聊天页面场景,一些第三方实现的下拉加载更多也可以实现类似功能,但 ...

  2. 下拉刷新及上拉加载更多的ListView

    PullToRefreshListView 自定义ListView 带简洁的下拉刷新及上拉加载更多功能 PullToRefreshListView 实现过程 使用方法 GIF效果 结束语 实现过程 继 ...

  3. Flutter ListView封装,下拉刷新、上拉加载更多

    Flutter ListView封装,下拉刷新.上拉加载更多 ​ 封装了Flutter的ListView,只要传递请求数据的方法和绘制item的方法进去就可以绘制ListView,同时支持下拉刷新.上 ...

  4. Flutter开发之ListView使用第三方flutter_refresh加载更多(37)

    在Flutter开发之ListView使用第三方pull_to_refresh加载更多(36) 中我们实现了下拉刷新.上拉分页加载的功能.今天介绍另一个ListView使用第三方flutter_ref ...

  5. Flutter开发之ListView使用第三方pull_to_refresh加载更多(36)

    在Flutter开发之ListView下拉刷新&上拉加载更多(35) 中我们实现了下拉刷新.上拉分页加载的功能.但是使用起来非常不方便,且不满一屏时难以处理. 今天介绍ListView使用第三 ...

  6. Flutter开发之ListView下拉刷新上拉加载更多(35)

    在Flutter开发之ListView组件(21) 文章中,我们了解了ListView组件的基本使用.但是数据比较少,没有涉及分页加载.而实际开发中,下拉刷新和分页加载几乎是所有APP的标配.在iOS ...

  7. 【Flutter】ListView 列表高级功能 ( ScrollController 上拉加载更多 )

    文章目录 一.ScrollController 上拉加载更多 二.ScrollController 使用流程 三.ScrollController 判定滑动到底部 四.完整代码示例 五.相关资源 一. ...

  8. Flutter ListView 下拉刷新与上拉加载更多

    ListView 下拉刷新与上拉加载更多 import 'dart:async'; import 'package:flutter/material.dart';/*** 有状态StatefulWid ...

  9. Flutter listview下拉刷新 上拉加载更多 功能实现

    下拉刷新 在Flutter中系统已经为我们提供了google material design的刷新功能 , 样式与原生Android一样. 我们可以使用RefreshIndicator组件来实现Flu ...

最新文章

  1. nginx的重定向,反向代理以及负载均衡
  2. Py之cx_Freeze:Python库之cx_Freeze库(程序打包)简介、安装、使用方法详细攻略—案例之实现机器人在线24小时智能翻译
  3. MySQL存储引擎之InnoDB
  4. 计算机使用技巧爆文,关于小红书爆文的10个小技巧
  5. java 对象克隆_JAVA对象克隆
  6. 关于Java的反射机制,你需要理解这些...
  7. 呵呵,幸亏当初选了这个BLOG
  8. python socket send_全网最详细python中socket套接字send与sendall的区别
  9. Java-虚拟机-启动参数及调优
  10. excel判断单元格包含指定内容的函数用=IF(COUNTIF(A1,*内容*),0,1)
  11. 【ArcGIS|空间分析|网络分析】9 使用位置分配选择最佳商店位置
  12. linux系统日志设置
  13. 让Google earth叠加中文地图
  14. 系统论重要模型_笔记
  15. 细数阿里 25 个开源的前端项目
  16. 测回角值计算用计算机,土木工程测量6-计算题库及参考答案
  17. 胆结石饮食有什么禁忌?4类食物要少吃
  18. 人在旅途——》张家界之旅:20190422
  19. Android自定义view摇杆,Android自定义摇杆
  20. 大datatable 内存一直涨_硬盘与内存报价单曝光了,疫情期间该不该给电脑升级?别弄错了...

热门文章

  1. boost::histogram::accumulators用法的测试程序
  2. boost::transpose_graph用法的测试程序
  3. VTK:Texture之TextureThreshold
  4. VTK:PolyData之WarpSurface
  5. VTK:模型之Delaunay3DDemo
  6. VTK:图片之ImageSobel2D
  7. VTK:图片之Flip
  8. OpenCV自定义CN跟踪器
  9. C++确定一个字符串是否是另一个字符串的排列的算法(附完整源码)
  10. OpenGL pointsprites点精灵的实例