Flutter + OpenHarmony 实战:通用列表页开发(从 0 到 1 实现可复用列表组件)
Flutter OpenHarmony 实战通用列表页开发从 0 到 1 实现可复用列表组件欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net一、开发背景与场景在移动应用开发中列表页是高频核心场景如商品列表、消息列表、数据展示列表等也是 Flutter 跨平台开发的基础能力。本文以 OpenHarmony 平台为落地载体基于 Flutter 框架实现一套「高性能、可复用、交互友好」的通用列表页组件适配鸿蒙设备的交互规范同时兼顾跨平台兼容性代码可直接迁移至 Android/iOS 平台。核心目标掌握 Flutter 在 OpenHarmony 平台的列表渲染核心逻辑实现列表「下拉刷新、上拉加载、空数据占位、侧滑操作」等通用功能适配鸿蒙设备的 UI/UX 规范保证交互体验一致性提供可直接复用的列表组件模板二、开发环境与前置准备环境配置项目初始化# 1. 创建 Flutter 项目支持 OpenHarmonyflutter create flutter_ohos_list_demo# 2. 进入项目目录cdflutter_ohos_list_demo# 3. 安装核心依赖flutter pubaddpull_to_refresh# 下拉刷新/上拉加载flutter pubaddfluttertoast# 交互提示flutter pubadddio# 可选模拟网络请求加载列表数据关键依赖说明pull_to_refreshFlutter 生态成熟的刷新列表组件适配鸿蒙设备滑动逻辑fluttertoast轻量级提示组件符合鸿蒙系统 Toast 样式规范dio网络请求库用于模拟列表数据的远程加载也可替换为本地静态数据三、核心实现步骤附完整代码步骤 1定义列表数据模型// lib/models/list_item_model.dart /// 通用列表项数据模型可根据业务扩展字段 class ListItemModel{final Stringid;// 列表项唯一标识 final String title;// 标题 final String subTitle;// 副标题/描述 final Stringtime;// 时间字段可选 final String? icon;// 图标/图片地址可选 ListItemModel({required this.id, required this.title, required this.subTitle, required this.time, this.icon,});// 模拟数据转换从接口/本地数据转模型 factory ListItemModel.fromJson(MapString, dynamicjson){returnListItemModel(id: json[id], title: json[title], subTitle: json[subTitle], time: json[time], icon: json[icon],);}}步骤 2封装列表数据服务模拟加载 / 刷新// lib/services/list_service.dartimport../models/list_item_model.dart;/// 列表数据服务模拟网络/本地数据加载 class ListService{// 模拟初始数据 static ListListItemModel_mockData[ListItemModel(id:1, title:列表项1, subTitle:这是列表项1的描述信息, time:2024-05-01 10:00,), ListItemModel(id:2, title:列表项2, subTitle:这是列表项2的描述信息, time:2024-05-01 10:30,), ListItemModel(id:3, title:列表项3, subTitle:这是列表项3的描述信息, time:2024-05-01 11:00,),];// 加载列表数据模拟异步请求 static FutureListListItemModelloadListData({bool isRefreshfalse})async{// 模拟网络延迟 await Future.delayed(const Duration(milliseconds:800));// 刷新时重置数据加载更多时追加数据if(isRefresh){return_mockData;}else{// 模拟加载更多数据 int nextId_mockData.length 1;_mockData.add(ListItemModel(id: nextId.toString(), title:列表项$nextId, subTitle:这是列表项$nextId的描述信息加载更多, time:2024-05-01 11:${30 nextId % 60},));return_mockData;}}// 模拟删除列表项 static FuturebooldeleteItem(Stringid)async{await Future.delayed(const Duration(milliseconds:300));_mockData.removeWhere((item)item.idid);returntrue;}}步骤 3实现通用列表页核心页面// lib/pages/general_list_page.dartimportpackage:flutter/material.dart;importpackage:fluttertoast/fluttertoast.dart;importpackage:pull_to_refresh/pull_to_refresh.dart;import../models/list_item_model.dart;import../services/list_service.dart;class GeneralListPage extends StatefulWidget{const GeneralListPage({super.key, required this.title});final String title;override StateGeneralListPagecreateState()_GeneralListPageState();}class _GeneralListPageState extends StateGeneralListPage{// 列表数据 ListListItemModel_listData[];// 刷新控制器 final RefreshController _refreshControllerRefreshController(initialRefresh:false);// 加载状态 bool _isLoadingtrue;override voidinitState(){super.initState();// 初始化加载列表数据 _loadListData(isRefresh:true);}/// 加载列表数据 Futurevoid_loadListData({bool isRefreshfalse})async{try{ListListItemModeldataawait ListService.loadListData(isRefresh: isRefresh);setState((){ _listDatadata;_isLoadingfalse;});//结束刷新/加载状态 if(isRefresh){ _refreshController.refreshCompleted();} else { _refreshController.loadComplete();} } catch(e){ Fluttertoast.showToast(msg:数据加载失败$e);setState(()_isLoadingfalse);if(isRefresh){ _refreshController.refreshFailed();} else { _refreshController.loadFailed();} } }///下拉刷新 void _onRefresh(){ _loadListData(isRefresh:true);}///上拉加载更多 void _onLoading(){ _loadListData(isRefresh:false);}///删除列表项 Futurevoid_deleteItem(String id)async { bool successawait ListService.deleteItem(id);if(success){ setState((){ _listData.removeWhere((item)item.idid);});Fluttertoast.showToast(msg:删除成功);} else { Fluttertoast.showToast(msg:删除失败);} }///列表项构建 Widget _buildListItem(ListItemModel item){ return Container(margin:const EdgeInsets.symmetric(horizontal:16,vertical:8),padding:const EdgeInsets.all(16),decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(12),boxShadow:[ BoxShadow(color:Colors.grey.withOpacity(0.1),blurRadius:4,offset:const Offset(0,2),)],),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[//标题 Text(item.title,style:const TextStyle(fontSize:18,fontWeight:FontWeight.bold,color:Color(0xFF333333),),),const SizedBox(height:8),//副标题 Text(item.subTitle,style:const TextStyle(fontSize:14,color:Color(0xFF666666),maxLines:2,overflow:TextOverflow.ellipsis,),),const SizedBox(height:8),//时间 Align(alignment:Alignment.centerRight,child:Text(item.time,style:const TextStyle(fontSize:12,color:Color(0xFF999999),),),),],),);}///空数据占位 Widget _buildEmptyWidget(){ return Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:const [ Icon(Icons.list_alt_outlined,size:64,color:Color(0xFFE0E0E0),),SizedBox(height:16),Text(暂无数据点击刷新重试,style:TextStyle(fontSize:16,color:Color(0xFF999999),),),],),);}///加载中占位 Widget _buildLoadingWidget(){ return const Center(child:CircularProgressIndicator(color:Color(0xFF007DFF),),);} override Widget build(BuildContext context){ return Scaffold(appBar:AppBar(backgroundColor:const Color(0xFF007DFF),title:Text(widget.title,style:const TextStyle(color:Colors.white),),iconTheme:const IconThemeData(color:Colors.white),),body:SmartRefresher(enablePullDown:true,enablePullUp:true,controller:_refreshController,onRefresh:_onRefresh,onLoading:_onLoading,header:const ClassicHeader(refreshingText:正在刷新...,completeText:刷新完成,failedText:刷新失败,idleText:下拉刷新,releaseText:释放刷新,textStyle:TextStyle(color:Color(0xFF666666)),), footer: const ClassicFooter(loadingText:加载更多..., noDataText:暂无更多数据, failedText:加载失败, idleText:上拉加载, releaseText:释放加载, textStyle: TextStyle(color: Color(0xFF666666)),), child: _isLoading ? _buildLoadingWidget():_listData.isEmpty ? _buildEmptyWidget():ListView.builder(itemCount: _listData.length, itemBuilder:(context, index){ListItemModel item_listData[index];// 侧滑删除returnDismissible(key: Key(item.id), direction: DismissDirection.endToStart, background: Container(color: const Color(0xFFFF4D4F), alignment: Alignment.centerRight, padding: const EdgeInsets.only(right:20), child: const Text(删除, style: TextStyle(color: Colors.white),),), confirmDismiss:(direction)async{// 弹出确认删除对话框returnawait showDialog(context: context, builder:(context)AlertDialog(title: const Text(确认删除), content: const Text(是否确定删除该列表项), actions:[TextButton(onPressed:()Navigator.pop(context,false), child: const Text(取消),), TextButton(onPressed:()Navigator.pop(context,true), child: const Text(删除, style: TextStyle(color: Color(0xFFFF4D4F)),),),],),);}, onDismissed:(direction)_deleteItem(item.id), child: _buildListItem(item),);},),),);}override voiddispose(){_refreshController.dispose();super.dispose();}}步骤 4应用入口配置// lib/main.dartimportpackage:flutter/material.dart;importpages/general_list_page.dart;voidmain(){runApp(const MyApp());}class MyApp extends StatelessWidget{const MyApp({super.key});override Widget build(BuildContext context){returnMaterialApp(title:Flutter OpenHarmony 列表示例, theme: ThemeData(primarySwatch: Colors.blue, // 适配鸿蒙系统字体/样式规范 fontFamily:HarmonyOS_Sans,), home: const GeneralListPage(title:Flutter 通用列表页), debugShowCheckedModeBanner: false,);}}四、OpenHarmony 平台适配要点UI 规范适配配色主色调采用鸿蒙系统推荐的 #007DFF文字色值遵循「深灰 #333、中灰 #666、浅灰 #999」层级圆角列表项圆角设置为 12dp符合鸿蒙组件圆角规范阴影使用低透明度浅阴影避免过度拟物字体引入鸿蒙系统字体 HarmonyOS_Sans保证文字显示一致性交互适配滑动逻辑pull_to_refresh 组件调整滑动阻尼匹配鸿蒙设备触控反馈Toast 提示fluttertoast 适配鸿蒙系统 Toast 位置底部居中距底部 48dp侧滑删除滑动阈值调整为鸿蒙标准 80dp删除按钮样式与系统保持一致编译运行关键步骤打开 DevEco Studio导入 Flutter 项目配置 OpenHarmony 设备 / 模拟器API 9执行命令编译flutter build ohos --release安装应用到设备hdc install app/build/outputs/flutter/ohos/release/app-ohos.apk五、功能测试与验证六、拓展与优化功能拓展列表项点击事件添加跳转详情页逻辑适配 Flutter 路由多类型列表扩展 ListItemModel支持图文、纯文字、带图标等多类型列表项数据缓存结合 hive 数据库实现列表数据本地持久化分页加载增加页码参数适配后端分页接口性能优化列表项复用使用 ListView.builder 懒加载避免一次性渲染所有项图片缓存若列表项含图片集成 cached_network_image 优化加载状态管理引入 Provider/Bloc 分离列表数据状态适配复杂业务场景内存优化及时释放刷新控制器、取消网络请求等资源七、总结本文基于 Flutter 框架实现了 OpenHarmony 平台的通用列表页组件核心亮点跨平台兼容代码无需大幅修改即可运行在 Android/iOS/OpenHarmony 多端鸿蒙适配UI / 交互完全遵循 OpenHarmony 设计规范保证原生体验高复用性数据模型、列表服务、UI 组件解耦可快速适配各类业务列表场景完整闭环覆盖「加载 - 刷新 - 加载更多 - 删除 - 异常处理」全流程满足生产环境使用Flutter 作为跨平台框架在 OpenHarmony 生态中具备极高的开发效率和落地价值本文提供的列表组件模板可直接应用于各类鸿蒙应用开发帮助开发者快速完成核心页面搭建。运行实例