ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flutter跨平台开发:鸿蒙购物清单应用实战

Flutter跨平台开发:鸿蒙购物清单应用实战 1. 项目概述Flutter跨平台鸿蒙购物清单应用购物清单应用是日常生活中非常实用的工具类应用能够帮助用户高效管理购物计划、精确计算购物预算。本项目使用Flutter框架开发实现了完整的商品管理、分类筛选、价格计算等功能特别针对鸿蒙系统进行了适配优化。作为一名有多年Flutter开发经验的工程师我发现购物类应用虽然看似简单但要开发出一个体验优秀、功能完善的产品需要考虑很多细节。比如商品价格的精确计算、分类筛选的交互设计、数据持久化的稳定性等。这个项目不仅适合Flutter初学者学习基础开发流程也包含了许多进阶技巧值得有一定经验的开发者参考。2. 环境准备与项目搭建2.1 Flutter开发环境配置首先需要确保你的开发环境已经正确配置了Flutter SDK。我推荐使用Flutter 3.41.9版本这个版本对鸿蒙系统的兼容性较好。安装完成后可以通过以下命令检查环境flutter doctor如果要在鸿蒙设备上运行还需要安装鸿蒙开发工具链。目前Flutter官方还没有正式支持鸿蒙OS但可以通过以下方式实现兼容使用鸿蒙的Java UI框架作为Flutter的渲染后端通过FFI调用鸿蒙的Native API使用鸿蒙的分布式能力扩展应用功能2.2 项目初始化创建一个新的Flutter项目flutter create shopping_list_harmony cd shopping_list_harmony然后添加项目所需的主要依赖dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 # 用于本地数据存储 intl: ^0.18.1 # 国际化支持 provider: ^6.0.5 # 状态管理3. 核心功能实现3.1 数据模型设计购物清单应用的核心是商品数据模型我们需要设计一个能够完整描述商品信息的类class ShoppingItem { final String id; final String name; final String category; final double price; final double quantity; final String unit; bool isPurchased; final DateTime addedDate; ShoppingItem({ required this.id, required this.name, required this.category, required this.price, required this.quantity, required this.unit, this.isPurchased false, required this.addedDate, }); double get totalPrice price * quantity; MapString, dynamic toJson() { return { id: id, name: name, category: category, price: price, quantity: quantity, unit: unit, isPurchased: isPurchased, addedDate: addedDate.toIso8601String(), }; } factory ShoppingItem.fromJson(MapString, dynamic json) { return ShoppingItem( id: json[id], name: json[name], category: json[category], price: json[price], quantity: json[quantity], unit: json[unit], isPurchased: json[isPurchased] ?? false, addedDate: DateTime.parse(json[addedDate]), ); } }这个模型包含了商品的基本信息以及购买状态、添加时间等元数据。特别注意price和quantity都使用double类型以支持小数数量的商品如0.5公斤。3.2 状态管理与数据持久化购物清单应用需要管理商品列表的状态并在应用关闭后能够恢复数据。我们使用shared_preferences插件实现本地存储class ShoppingListProvider with ChangeNotifier { ListShoppingItem _items []; ListShoppingItem get items _items; Futurevoid loadItems() async { final prefs await SharedPreferences.getInstance(); final itemsJson prefs.getStringList(shopping_items) ?? []; _items itemsJson .map((json) ShoppingItem.fromJson(jsonDecode(json))) .toList(); notifyListeners(); } Futurevoid saveItems() async { final prefs await SharedPreferences.getInstance(); final itemsJson _items.map((item) jsonEncode(item.toJson())).toList(); await prefs.setStringList(shopping_items, itemsJson); } void addItem(ShoppingItem item) { _items.add(item); saveItems(); notifyListeners(); } void togglePurchased(String id) { final index _items.indexWhere((item) item.id id); if (index ! -1) { _items[index].isPurchased !_items[index].isPurchased; saveItems(); notifyListeners(); } } void removeItem(String id) { _items.removeWhere((item) item.id id); saveItems(); notifyListeners(); } void clearPurchased() { _items.removeWhere((item) item.isPurchased); saveItems(); notifyListeners(); } }在实际开发中我发现直接使用SharedPreferences存储大量数据可能会导致性能问题。当商品数量超过100时建议考虑使用SQLite或Hive等更专业的本地存储方案。3.3 用户界面实现3.3.1 主界面布局主界面采用经典的Material Design布局包含以下几个部分顶部的金额汇总卡片中部的分类筛选栏底部的商品列表右下角的添加商品按钮class ShoppingListScreen extends StatelessWidget { override Widget build(BuildContext context) { final provider Provider.ofShoppingListProvider(context); return Scaffold( appBar: AppBar( title: Text(购物清单), actions: [ IconButton( icon: Icon(Icons.delete_sweep), onPressed: () _showClearDialog(context), ), ], ), body: Column( children: [ _buildSummaryCard(provider), _buildCategoryFilter(provider), Expanded( child: provider.items.isEmpty ? _buildEmptyState() : _buildItemList(provider), ), ], ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () _showAddItemDialog(context), ), ); } }3.3.2 金额汇总卡片金额汇总卡片显示待购金额、已购金额和待购商品数量帮助用户快速了解购物情况Widget _buildSummaryCard(ShoppingListProvider provider) { final totalPrice provider.items .where((item) !item.isPurchased) .fold(0.0, (sum, item) sum item.totalPrice); final purchasedPrice provider.items .where((item) item.isPurchased) .fold(0.0, (sum, item) sum item.totalPrice); final unpurchasedCount provider.items .where((item) !item.isPurchased) .length; return Card( margin: EdgeInsets.all(16), elevation: 4, child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue.shade400, Colors.blue.shade600], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(待购金额, style: TextStyle(color: Colors.white70)), Text( ¥${totalPrice.toStringAsFixed(2)}, style: TextStyle( color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold, ), ), ], ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text(待购 $unpurchasedCount 件, style: TextStyle(color: Colors.white70)), Text(已购 ¥${purchasedPrice.toStringAsFixed(2)}, style: TextStyle(color: Colors.white70)), ], ), ], ), ), ); }3.3.3 商品列表项每个商品项显示商品名称、分类、数量、单价和小计并提供复选框标记购买状态Widget _buildItemCard(ShoppingItem item, ShoppingListProvider provider) { return Card( margin: EdgeInsets.only(bottom: 12), child: ListTile( leading: Checkbox( value: item.isPurchased, onChanged: (value) provider.togglePurchased(item.id), ), title: Text( item.name, style: TextStyle( fontWeight: FontWeight.bold, decoration: item.isPurchased ? TextDecoration.lineThrough : null, color: item.isPurchased ? Colors.grey : null, ), ), subtitle: Text( ${item.category} · ${item.quantity}${item.unit} × ¥${item.price.toStringAsFixed(2)}, ), trailing: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( ¥${item.totalPrice.toStringAsFixed(2)}, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: item.isPurchased ? Colors.grey : Colors.blue.shade700, ), ), IconButton( icon: Icon(Icons.delete_outline, size: 20), onPressed: () provider.removeItem(item.id), ), ], ), ), ); }4. 鸿蒙系统适配与优化4.1 鸿蒙特性集成虽然Flutter应用在鸿蒙系统上可以正常运行但要充分发挥鸿蒙的特性需要进行一些特殊适配分布式能力通过鸿蒙的分布式软总线可以实现手机和平板之间的购物清单同步原子化服务将常用功能如快速添加商品作为鸿蒙的原子化服务提供卡片功能开发鸿蒙服务卡片在桌面显示待购商品数量和金额4.2 性能优化建议在鸿蒙设备上运行Flutter应用时可以采取以下优化措施减少Widget重建使用const构造函数和Provider的select方法列表性能优化使用ListView.builder并设置合适的cacheExtent图片资源优化使用.9图适配不同屏幕尺寸内存管理及时释放不用的资源避免内存泄漏5. 项目扩展与进阶功能5.1 购物历史记录扩展数据模型记录每次购物的情况class ShoppingHistory { final String id; final DateTime date; final ListShoppingItem items; final double totalAmount; final String? notes; ShoppingHistory({ required this.id, required this.date, required this.items, required this.totalAmount, this.notes, }); }5.2 预算管理功能添加预算管理模块帮助用户控制消费class BudgetManager { double monthlyBudget 1000.0; double getRemainingBudget(double spent) { return monthlyBudget - spent; } double getBudgetProgress(double spent) { return (spent / monthlyBudget).clamp(0.0, 1.0); } String getBudgetStatus(double spent) { final progress getBudgetProgress(spent); if (progress 1.0) return 预算已超支; if (progress 0.9) return 预算即将用完; if (progress 0.7) return 预算使用较多; return 预算充足; } }5.3 条码扫描功能集成条码扫描功能快速添加商品import package:mobile_scanner/mobile_scanner.dart; class BarcodeScannerPage extends StatelessWidget { override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(扫描条码)), body: MobileScanner( onDetect: (capture) { final barcode capture.barcodes.first.rawValue; if (barcode ! null) { Navigator.pop(context, barcode); } }, ), ); } }6. 测试与调试6.1 单元测试示例编写单元测试验证核心逻辑void main() { group(ShoppingItem, () { test(totalPrice calculation, () { final item ShoppingItem( id: 1, name: Apple, category: Fruit, price: 5.0, quantity: 3.0, unit: 个, addedDate: DateTime.now(), ); expect(item.totalPrice, 15.0); }); }); group(ShoppingListProvider, () { late ShoppingListProvider provider; setUp(() { provider ShoppingListProvider(); }); test(add and remove item, () { final item ShoppingItem(...); provider.addItem(item); expect(provider.items.length, 1); provider.removeItem(item.id); expect(provider.items.length, 0); }); }); }6.2 Widget测试测试UI组件的交互行为void main() { testWidgets(Add item dialog test, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: Builder( builder: (context) TextButton( child: Text(Add), onPressed: () showDialog( context: context, builder: (_) AddItemDialog(), ), ), ), ), ), ); await tester.tap(find.text(Add)); await tester.pumpAndSettle(); expect(find.text(添加商品), findsOneWidget); }); }7. 项目部署与发布7.1 鸿蒙应用打包虽然Flutter官方尚未直接支持鸿蒙应用打包但可以通过以下步骤实现使用Flutter构建Android APK使用鸿蒙的APK转换工具将Android应用转换为鸿蒙应用添加鸿蒙特有的元数据和权限使用鸿蒙的签名工具对应用进行签名7.2 应用商店发布将打包好的应用发布到华为应用市场注册华为开发者账号准备应用元数据图标、截图、描述等提交应用审核通过后即可上架8. 常见问题与解决方案8.1 数据同步问题问题在多设备间同步购物清单时可能出现冲突解决方案使用时间戳作为最后修改时间的标记实现冲突解决策略如最后修改优先提供手动解决冲突的界面8.2 性能问题问题商品数量多时界面卡顿解决方案实现分页加载使用Isolate处理大量计算优化列表项的构建方式8.3 鸿蒙兼容性问题问题某些Flutter插件在鸿蒙上无法正常工作解决方案检查插件是否依赖Android特定API寻找替代插件或自行实现功能通过MethodChannel调用鸿蒙原生API9. 项目总结与经验分享通过这个购物清单应用的开发我总结了以下几点经验状态管理对于中等复杂度的应用Provider是一个简单有效的选择。但对于更复杂的场景考虑使用Riverpod或Bloc。数据持久化SharedPreferences适合存储简单数据但复杂数据结构建议使用Hive或SQLite。鸿蒙适配目前Flutter在鸿蒙上的支持还在完善中需要针对性地解决一些兼容性问题。性能优化列表性能是关键务必使用ListView.builder并合理设置cacheExtent。测试覆盖良好的测试覆盖率能大大减少后期维护成本特别是核心业务逻辑。这个项目还有很多可以扩展的方向比如添加云端同步功能实现智能推荐商品集成支付功能开发手表版应用希望这个教程能帮助你掌握Flutter跨平台开发的基本流程并为鸿蒙应用开发打下基础。在实际开发中最重要的是保持代码的可维护性和可扩展性这样才能应对不断变化的需求。
返回列表