Flutter-OH 列表下拉刷新功能开发与实战
本次为 Flutter 鸿蒙工程的列表集成了下拉刷新功能,选择了 Flutter 主流的库进行适配,实现了下拉刷新数据的功能,解决了鸿蒙端手势交互与动画兼容问题。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
前言
网络功能开发完成后,接下来就是最常用的列表下拉刷新功能,这是所有数据类应用的标配功能。Flutter 原生的下拉刷新组件在鸿蒙端基本可以正常使用,但在实际开发过程中还是会遇到一些鸿蒙端特有的适配问题,需要做少量调整才能达到完美的效果。
本文将完整记录 Flutter 鸿蒙应用列表下拉刷新功能的开发全流程,从组件选型、列表搭建、刷新集成到状态管理,每一步都附带完整可复用的代码,同时整理开发过程中遇到的所有问题和对应的解决方案,每个问题都附带完整解决代码,帮大家快速完成下拉刷新功能的开发。
一、下拉刷新组件选型
Flutter 开发下拉刷新有多种方案,经过实际测试,推荐使用官方的RefreshIndicator组件,这是对鸿蒙端兼容性最好的方案,不需要额外引入第三方依赖,性能稳定,适配成本最低。
| 组件方案 | 鸿蒙兼容性 | 优点 | 缺点 |
| 官方 RefreshIndicator | 99% 兼容 | 无依赖、性能好、适配成本低 | 样式自定义程度一般 |
| 第三方 flutter_easyrefresh | 80% 兼容 | 样式丰富 | 鸿蒙端存在手势冲突问题 |
| 自定义下拉刷新 | 100% 兼容 | 完全自定义 | 开发成本高 |
综合考虑,优先选择官方RefreshIndicator组件,完全满足常规业务需求,适配成本最低。
二、基础列表页面搭建
先搭建基础的列表页面,实现静态列表展示,为后续添加下拉刷新做准备。
2.1 列表数据实体类
创建列表数据的实体类,用于解析接口返回的数据:
class ListItem {
int id;
String title;
String content;
ListItem({
required this.id,
required this.title,
required this.content,
});
factory ListItem.fromJson(Map<String, dynamic> json) {
return ListItem(
id: json["id"],
title: json["title"],
content: json["content"],
);
}
}
2.2 基础列表页面实现
实现基础的列表页面,使用ListView.builder构建列表:
import 'package:flutter/material.dart';
class RefreshListPage extends StatefulWidget {
const RefreshListPage({super.key});
@override
State<RefreshListPage> createState() => _RefreshListPageState();
}
class _RefreshListPageState extends State<RefreshListPage> {
List<ListItem> dataList = [];
@override
void initState() {
super.initState();
// 初始化模拟数据
initMockData();
}
// 初始化模拟数据
void initMockData() {
for (int i = 0; i < 10; i++) {
dataList.add(ListItem(
id: i,
title: "列表标题$i",
content: "这是列表的第$i条内容",
));
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("下拉刷新列表"),
centerTitle: true,
),
body: ListView.builder(
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].title),
subtitle: Text(dataList[index].content),
);
},
),
);
}
}
三、下拉刷新功能集成
在基础列表的基础上,集成RefreshIndicator组件,实现下拉刷新功能。
3.1 刷新组件集成
用RefreshIndicator包裹 ListView,添加下拉刷新功能:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("下拉刷新列表"),
centerTitle: true,
),
body: RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].title),
subtitle: Text(dataList[index].content),
);
},
),
),
);
}
3.2 刷新回调方法实现
实现刷新回调方法,模拟网络请求刷新数据:
Future<void> _onRefresh() async {
// 模拟网络请求延迟
await Future.delayed(const Duration(seconds: 2));
// 清空原有数据,添加新数据
dataList.clear();
for (int i = 0; i < 10; i++) {
dataList.add(ListItem(
id: i,
title: "刷新后的标题$i",
content: "这是刷新后的第$i条内容",
));
}
setState(() {});
}
四、刷新状态管理
添加刷新状态管理,优化用户体验,避免重复刷新。
4.1 刷新状态变量定义
定义刷新状态变量,控制刷新状态:
bool isRefreshing = false;
4.2 状态控制逻辑优化
优化刷新回调,添加状态控制:
Future<void> _onRefresh() async {
if (isRefreshing) return;
isRefreshing = true;
setState(() {});
try {
await Future.delayed(const Duration(seconds: 2));
dataList.clear();
for (int i = 0; i < 10; i++) {
dataList.add(ListItem(
id: i,
title: "刷新后的标题$i",
content: "这是刷新后的第$i条内容",
));
}
} finally {
isRefreshing = false;
setState(() {});
}
}
五、数据刷新逻辑实现
对接之前开发的网络请求功能,实现真实接口数据的刷新。
5.1 接口数据刷新实现
对接网络请求,获取真实数据刷新列表:
Future<void> _onRefresh() async {
if (isRefreshing) return;
isRefreshing = true;
setState(() {});
try {
// 调用网络请求获取最新数据
var response = await HttpRequest().get("/list", params: {"page": 1, "size": 10});
dataList.clear();
for (var item in response.data) {
dataList.add(ListItem.fromJson(item));
}
} catch (e) {
print("刷新失败:$e");
} finally {
isRefreshing = false;
setState(() {});
}
}
六、开发过程中遇到的问题与解决方案
6.1 问题:鸿蒙端下拉刷新手势不触发
- 问题现象:在鸿蒙真机上,下拉列表没有反应,无法触发刷新回调
- 解决方案: ① 给 ListView 添加
AlwaysScrollableScrollPhysics物理滚动属性,确保列表始终可以滚动 ② 确保 ListView 的内容高度超过屏幕高度,内容不足时无法触发下拉 ③ 不要给 ListView 添加shrinkWrap: true属性,会导致滚动失效 - 完整解决代码:
ListView.builder(
// 关键配置:添加始终可滚动的物理属性
physics: const AlwaysScrollableScrollPhysics(),
// 禁止添加shrinkWrap: true
// shrinkWrap: true, ❌ 不要加这个
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].title),
subtitle: Text(dataList[index].content),
);
},
)
6.2 问题:刷新指示器不显示
- 问题现象:下拉时没有显示刷新的加载指示器
- 解决方案:
- ① 确保
RefreshIndicator是 ListView 的直接父组件,不要嵌套过多层级 - ② 不要修改
RefreshIndicator的默认颜色和高度,鸿蒙端自定义样式会有兼容问题 - ③ 确保刷新回调方法是异步方法,返回 Future 类型
- 完整解决代码:
RefreshIndicator(
// 不要自定义颜色和样式,使用默认样式
// color: Colors.red, ❌ 鸿蒙端自定义颜色会有兼容问题
// strokeWidth: 4, ❌ 不要修改默认线宽
onRefresh: _onRefresh, // 必须是返回Future的异步方法
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].title),
subtitle: Text(dataList[index].content),
);
},
),
)
6.3 问题:刷新完成后列表不更新
- 问题现象:刷新完成后,列表内容没有变化
- 解决方案:
- ① 刷新数据后必须调用
setState更新状态 - ② 确保数据列表是重新赋值,而不是只修改列表内的元素
- ③ 不要使用常量列表,必须是可变的 List 对象
- 完整解决代码:
Future<void> _onRefresh() async {
await Future.delayed(const Duration(seconds: 2));
// 正确做法:清空后重新添加数据,然后调用setState
dataList.clear();
for (int i = 0; i < 10; i++) {
dataList.add(ListItem(
id: i,
title: "刷新后的标题$i",
content: "这是刷新后的第$i条内容",
));
}
// 必须调用setState更新UI
setState(() {});
}
6.4 问题:下拉刷新和鸿蒙系统手势冲突
- 问题现象:下拉时触发了系统的返回手势,无法触发刷新
- 解决方案:
- ① 调整下拉触发的距离,修改
RefreshIndicator的displacement属性为 50 - ② 不要在页面边缘添加下拉刷新,避免和系统边缘返回手势冲突
- ③ 优先使用官方组件,第三方组件的手势冲突问题更严重
- 完整解决代码:
RefreshIndicator(
// 调整下拉触发距离,避免和系统手势冲突
displacement: 50,
onRefresh: _onRefresh,
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].title),
subtitle: Text(dataList[index].content),
);
},
),
)
七、真机功能测试
功能开发完成后,在真机上进行完整测试:
- 测试下拉手势是否正常触发刷新
- 测试刷新指示器显示是否正常
- 测试刷新完成后列表数据是否更新
- 测试快速重复下拉是否会出现重复刷新
- 测试网络异常情况下的刷新容错
所有测试项通过即代表下拉刷新功能开发完成。
八、功能开发总结
Flutter 鸿蒙端下拉刷新功能的开发,核心注意点总结如下:
- 优先使用官方
RefreshIndicator组件,兼容性最好,不要盲目使用第三方组件 - 必须给 ListView 添加
AlwaysScrollableScrollPhysics属性,否则鸿蒙端无法触发刷新 - 尽量不要自定义刷新指示器样式,默认样式在鸿蒙端的兼容性最好
- 添加刷新状态管理,避免用户快速重复下拉导致的重复请求问题
- 所有功能必须在真机上测试,模拟器上的手势和真机有差异
下拉刷新是最常用的基础功能,封装好之后可以在所有列表页面复用,后续的上拉加载功能也可以基于此扩展。
更多推荐
所有评论(0)