【开源鸿蒙跨平台开发先锋训练营】Flutter实现列表上拉加载和下拉刷新
Flutter实现鸿蒙App列表分页加载与刷新功能 本文介绍如何使用Flutter框架实现鸿蒙App中的列表分页加载和下拉刷新功能。通过新增_displayImages分页展示列表和_pageSize等分页控制属性,实现了两种展示模式:单列垂直PageView和两列GridView。关键功能包括下拉刷新_refreshData()重置数据、上拉加载_loadMore()追加数据,以及网格视图滚动监
学习目标:
本帖主要学习和交流通过Flutter框架实现鸿蒙App 列表的上架加载和下拉刷新的功能
这篇帖子是基于上一篇【开源鸿蒙跨平台开发先锋训练营】使用Flutter请求网络接口并渲染页面 的基础上学习和开发的。
公开代码也可以前往【开源鸿蒙跨平台开发先锋训练营】使用Flutter框架搭建鸿蒙App项目及代码管理中查看
下拉刷新与上拉加载(分页,每页 10 条)
概述
本次修改在 HomePage 中添加了下拉刷新与上拉加载(本地分页,每页 10 条),支持两种展示模式:单列垂直 PageView 与两列 GridView。目的是:平滑的用户交互、自动按需加载、并提供简单的保护以避免重复触发。
变更清单
-
为实现上拉加载和下拉刷新刷新,特新增了下面的属性:
_displayImages:当前用于展示的分页图片列表。_pageSize:每页条数,设为 10。_currentPage、_hasMore、_isLoadingMore:分页状态控制。_gridScrollController:用于 GridView 的滚动监听以实现上拉加载。
// 原始完整图片列表(从 API 解析得到) List<String> _images = []; // 当前用于展示的分页图片列表 List<String> _displayImages = []; // 分页相关 final int _pageSize = 10; // 每页 10 条 int _currentPage = 0; // 已加载页数 bool _hasMore = false; // 是否还有更多数据 bool _isLoadingMore = false; // 是否正在加载更多 bool _isLoading = true; String? _errorMessage; int _currentIndex = 0; bool _isGridView = false; // 显示模式:false=单列滑动,true=2列网格 final ScrollController _gridScrollController = ScrollController(); -
新增方法:
_refreshData():下拉刷新,重置分页并重新请求数据。_loadMore():计算 slice 并追加到_displayImages,更新分页状态。_onGridScroll():GridView 滚动监听方法,在接近底部时触发_loadMore()。
/// 下拉刷新,重新请求并重置分页 Future<void> _refreshData() async { setState(() { _errorMessage = null; _isLoading = true; }); _displayImages.clear(); _currentPage = 0; _hasMore = false; await _loadData(); }/// 加载下一页数据(内部分页) Future<void> _loadMore() async { if (_isLoadingMore) return; if (_images.isEmpty) return; setState(() { _isLoadingMore = true; }); // 计算下一页的区间并追加到展示列表 final nextPage = _currentPage + 1; final start = (nextPage - 1) * _pageSize; final end = (start + _pageSize) < _images.length ? (start + _pageSize) : _images.length; // 如果没有新数据可加,直接结束 if (start >= _images.length) { setState(() { _hasMore = false; _isLoadingMore = false; }); return; }void _onGridScroll() { if (_gridScrollController.position.extentAfter < 300 && _hasMore && !_isLoadingMore) { _loadMore(); } } -
更新方法:
_loadData():由原来直接将全部解析结果赋值,改为先保存完整_images,然后调用_loadMore()加载第一页(每页 10 条)。initState():添加_gridScrollController监听器。dispose():释放_gridScrollController。
/// 加载数据
Future<void> _loadData() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
print('开始加载数据...');
// 1. 获取原始 JavaScript 数据
print('正在请求网络数据...');
final jsData = await _apiService.getMockData();
print('网络请求完成,数据类型: ${jsData.runtimeType}');
// 2. 确保数据是字符串格式
final jsContent = jsData is String ? jsData : jsData.toString();
print('数据长度: ${jsContent.length}');
// 3. 解析数据并提取图片
print('开始解析数据...');
final result = await DataParser.parseWorksAndImages(jsContent);
print('数据解析完成');
// 4. 获取所有图片 URL
final allImages = result['images'] as List<String>;
// 调试:打印图片数量和前几个URL
print('加载到 ${allImages.length} 张图片');
if (allImages.isNotEmpty) {
print('第一张图片URL: ${allImages[0]}');
print('第一张图片URL长度: ${allImages[0].length}');
print('第一张图片URL是否为空: ${allImages[0].isEmpty}');
} else {
print('警告:图片列表为空!');
}
// 将原始列表保存,并初始化分页展示数据(每页 10 条)
_images = allImages;
_displayImages.clear();
_currentPage = 0;
_hasMore = _images.length > 0;
// 加载首页数据
await _loadMore();
setState(() {
_isLoading = false;
});
print('数据加载完成,UI已更新');
} catch (e, stackTrace) {
print('加载数据时出错: $e');
print('错误堆栈: $stackTrace');
setState(() {
_errorMessage = '加载失败: $e';
_isLoading = false;
});
}
}
- UI 修改:
- 在主体最外层使用
RefreshIndicator以支持下拉刷新。 - 使用
_displayImages作为PageView与GridView的数据源。 - 当
_isLoadingMore为 true 时在底部显示圆形进度作为加载指示器。 - PageView 在接近已加载末尾(index >= length - 2)时触发
_loadMore()。
- 在主体最外层使用
关键字段与方法说明
- 原始与展示列表:
_images(全部数据)_displayImages(已加载用于展示)
- 分页配置:
_pageSize = 10 - 加载控制:
_currentPage,_hasMore,_isLoadingMore - 刷新:
_refreshData()— 完整重置并调用_loadData() - 加载更多:
_loadMore()— 计算起止索引并追加到_displayImages,更新_currentPage与_hasMore
网格滚动监听:_gridScrollController + _onGridScroll()(当 extentAfter < 300 时触发)
用户可感知的行为
- 首次加载:页面启动或
HomePage打开时,_loadData()请求数据并以本地分页的方式加载第一页(最多 10 条)。 - 下拉刷新:任意可滚动视图下拉会触发
RefreshIndicator调用_refreshData(),完成后显示最新第一页数据。 - 上拉加载(Grid):在网格视图滚动到底部时,会自动加载更多数据并追加到当前列表。
- 上拉加载(PageView):在翻页到接近当前已加载末尾时会自动加载下一页。
- 加载状态:加载更多时会在页面底部显示一个小圆形进度条。
测试步骤
-
运行应用并进入首页。

-
验证首次加载:看到加载指示后展示不超过 10 张图片。
-
下拉刷新:在任一视图向下拉,观察是否重新请求并回到第一页数据。

-
Grid 上拉:切换到 Grid,滚动到底部,确认触发加载并追加新图片(直至无更多)。

-
PageView 自动加载:市面上大部分应用都做了这块体验上的优化,当接近末尾应自动加载下一页。
-
边界测试:当总数据 < 10 时确认无额外请求;当数据为空时显示“暂无数据”。
以下几点需要注意
- 当前实现是先解析并保留完整图片 URL 列表(
_images),然后在客户端按页加载,这会占用内存。,如果有合适的后端分页接口,改为服务端分页以减少内存与初始延迟。 - 已用
_isLoadingMore防止重复触发。
结束语
感谢阅读本帖,如对贴中内容有意见和建议的,欢迎与我联系交流,也欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)