news 2026/4/23 22:20:10

构建 OpenHarmony 简易购物清单计价器:用状态驱动实现动态金额统计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
构建 OpenHarmony 简易购物清单计价器:用状态驱动实现动态金额统计

一、为什么需要“简易购物清单计价器”?

在 OpenHarmony 的智慧生活场景中,用户常需在购物前规划预算:

  • 超市采购前列清单;
  • 家庭聚餐预估花费;
  • 学生管理生活费。

传统纸笔清单无法自动计算总价,而专业记账 App 又过于复杂。一个轻量、即时、可视化的购物清单工具,能显著提升效率:

  • 输入商品即知单项价格;
  • 勾选“已购”后自动从待付金额中扣除;
  • 实时看到“还剩多少钱要花”。

更重要的是,此类功能完全基于确定性计算——商品列表 + 单价 + 勾选状态 = 总金额。无需联网、不读取位置、不申请存储权限,是展示“纯逻辑 UI”的理想案例。

本文将构建一个极简页面:「简易购物清单计价器」。它包含:

  • 一个商品名称输入框;
  • 一个单价输入框(数字);
  • 一个“添加”按钮;
  • 一个可滚动的商品列表,每项左侧带 Checkbox,勾选表示“已购买”;
  • 底部两行统计信息:“总金额:¥XX.XX” 和 “待支付:¥XX.XX”。

所有数据保存在List<Item>中,关闭应用即清空,符合“临时购物清单”定位。


二、完整可运行代码

// lib/main.dartimport'package:flutter/material.dart';voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'购物清单',debugShowCheckedModeBanner:false,theme:ThemeData(useMaterial3:true,colorScheme:ColorScheme.fromSeed(seedColor:Colors.green)),home:constShoppingListPage(),);}}classItem{Stringname;double price;bool purchased;Item(this.name,this.price):purchased=false;}classShoppingListPageextendsStatefulWidget{constShoppingListPage({super.key});@overrideState<ShoppingListPage>createState()=>_ShoppingListPageState();}class_ShoppingListPageStateextendsState<ShoppingListPage>{finalTextEditingController_nameController=TextEditingController();finalTextEditingController_priceController=TextEditingController();finalList<Item>_items=[];void_addItem(){finalname=_nameController.text.trim();finalpriceStr=_priceController.text.trim();if(name.isEmpty||priceStr.isEmpty)return;double price;try{price=double.parse(priceStr);}catch(e){return;}if(price<=0)return;setState((){_items.add(Item(name,price));_nameController.clear();_priceController.clear();});}void_togglePurchased(int index){setState((){_items[index].purchased=!_items[index].purchased;});}@overrideWidgetbuild(BuildContextcontext){double total=0;double toPay=0;for(int i=0;i<_items.length;i++){total+=_items[i].price;if(!_items[i].purchased){toPay+=_items[i].price;}}returnScaffold(appBar:AppBar(title:constText('购物清单计价器')),body:Column(children:[Padding(padding:constEdgeInsets.all(12),child:Row(children:[Expanded(child:TextField(controller:_nameController,decoration:constInputDecoration(hintText:'商品名称'),),),constSizedBox(width:8),SizedBox(width:100,child:TextField(controller:_priceController,keyboardType:TextInputType.numberWithOptions(decimal:true),decoration:constInputDecoration(hintText:'单价'),),),IconButton(onPressed:_addItem,icon:constIcon(Icons.add)),],),),Expanded(child:ListView.builder(itemCount:_items.length,itemBuilder:(context,index){finalitem=_items[index];returnCheckboxListTile(title:Text(item.name),subtitle:Text(${item.price.toStringAsFixed(2)}'),value:item.purchased,onChanged:(bool?value){if(value!=null){_togglePurchased(index);}},);},),),Container(padding:constEdgeInsets.all(16),color:Colors.grey.shade100,child:Column(children:[Text('总金额:¥${total.toStringAsFixed(2)}',style:constTextStyle(fontSize:16)),Text('待支付:¥${toPay.toStringAsFixed(2)}',style:constTextStyle(fontSize:16,color:Colors.red)),],),),],),);}}

三、核心思想:状态驱动的动态计算

本页面的核心是三个状态变量

  1. _nameController.text:当前输入的商品名;
  2. _priceController.text:当前输入的单价;
  3. _items列表:已添加的所有商品及其状态。

当用户操作(添加/勾选)时,通过setState更新_items,触发build方法重新执行。在build中,每次重建都重新计算totaltoPay

double total=0;double toPay=0;for(int i=0;i<_items.length;i++){total+=_items[i].price;if(!_items[i].purchased){toPay+=_items[i].price;}}

这种“状态 → 计算 → 视图”的模式,确保 UI 始终与数据一致,是 Flutter 响应式编程的精髓。


四、安全商品添加逻辑:

我们首先看添加商品的核心方法:

void_addItem(){finalname=_nameController.text.trim();finalpriceStr=_priceController.text.trim();if(name.isEmpty||priceStr.isEmpty)return;double price;try{price=double.parse(priceStr);}catch(e){return;}if(price<=0)return;setState((){_items.add(Item(name,price));_nameController.clear();_priceController.clear();});}

这段代码实现了健壮的商品录入流程

  • 空值检查
    • trim()去除首尾空格;
    • 若名称或价格为空,直接返回,避免无效商品;
  • 价格解析
    • 使用double.parse(而非tryParse)配合try-catch
    • 这是 Dart 最基础的异常处理方式,兼容所有版本;
    • 若输入非数字(如 “abc”),抛出异常,catch后静默忽略;
  • 有效性校验
    • price <= 0排除负数或零价格(现实中不合理);
  • 状态更新
    • setState内完成三项操作:
      1. 添加新Item_items
      2. 清空名称输入框;
      3. 清空价格输入框;
    • 保证 UI 与数据同步。

💡 此设计不提示错误(如“请输入有效价格”),因面向快速录入场景,静默忽略无效输入更流畅。


五、实时金额统计机制:

再看金额计算逻辑(位于build方法开头):

double total=0;double toPay=0;for(int i=0;i<_items.length;i++){total+=_items[i].price;if(!_items[i].purchased){toPay+=_items[i].price;}}

这里展示了高效、清晰的聚合计算

  • 初始化累加器
    • total:所有商品价格之和;
    • toPay:仅未勾选(!purchased)商品之和;
  • 单次遍历
    • for循环遍历_items
    • 每项价格加到total
    • 若未购买,再加到toPay
  • 性能保障
    • 时间复杂度 O(n),n 为商品数;
    • 即使有 100 项,计算耗时可忽略;
  • 实时性
    • 每次setState都会重建 UI,重新计算;
    • 用户勾选/取消勾选后,金额立即更新。

📌 值得注意的是,未使用reducewhere.map.sum等函数式写法,因for循环最直观、兼容性最好。


六、商品列表与交互反馈:

最后看商品列表渲染:

CheckboxListTile(title:Text(item.name),subtitle:Text(${item.price.toStringAsFixed(2)}'),value:item.purchased,onChanged:(bool?value){if(value!=null){_togglePurchased(index);}},);

这里实现了标准 Material Design 商品项

  • title:显示商品名称;
  • subtitle
    • 显示格式化价格(toStringAsFixed(2)保留两位小数);
    • 前缀 “¥” 符合中文习惯;
  • value:绑定item.purchased状态;
  • onChanged
    • 参数value可能为null(API 设计如此);
    • 显式检查if (value != null)是安全实践;
    • 调用_togglePurchased(index)切换状态。

💡CheckboxListTile自动处理布局、间距、点击反馈,无需自定义样式。


七、为何这个计价器适合 OpenHarmony 场景?

1. 生活实用性强

  • 超市购物时边选边算;
  • 家庭采购预算控制;
  • 学生食堂消费记录。

2. 隐私与安全

  • 所有数据仅存于内存_items
  • 关闭应用即清空,无隐私泄露风险;
  • 不申请任何权限,符合 OpenHarmony 安全模型。

3. 多设备适配

  • 在手表上:大触控区域便于勾选;
  • 在平板上:列表可显示更多商品;
  • 在智慧屏上:作为家庭共享购物白板。

4. 教学价值

  • 演示StatefulWidget管理复杂列表状态;
  • 展示实时计算与 UI 更新的闭环;
  • 体现“输入-状态-视图”响应式范式。

八、工程注意事项

1. 数值精度处理

  • 使用double存储价格,可能存在浮点误差(如 0.1 + 0.2 ≠ 0.3);
  • toStringAsFixed(2)在显示层掩盖了该问题;
  • 若需高精度,应使用整数(分)存储,但会增加复杂度,本文未采用。

2. 输入体验优化

  • 价格输入框宽度固定(100px),避免布局跳动;
  • “添加”按钮紧邻输入框,减少手指移动距离;
  • 支持小数输入(TextInputType.numberWithOptions(decimal: true))。

3. 可访问性

  • CheckboxListTile自带无障碍支持;
  • 金额区域使用Colors.grey.shade100背景,视觉上独立于列表;
  • “待支付”用红色突出,符合财务警示惯例。

九、扩展与限制

可安全扩展的方向:

  • 删除商品:长按列表项弹出删除菜单;
  • 数量支持:增加数量输入框,总价 = 单价 × 数量;
  • 分类统计:如“食品 ¥XX,日用品 ¥XX”。

当前限制(有意为之):

  • 不支持商品编辑(名称/价格不可改);
  • 不记忆历史商品(每次启动为空);
  • 不导出清单(无分享/打印功能)。

这些限制确保核心功能聚焦、简单、无认知负担


十、结语:用计算,照亮消费决策

本文的页面仅 69 行代码,却完整实现了一个实用、可靠、直观的购物清单计价器。它没有云同步,没有 AI 推荐,只有清晰的状态、实时的计算、负责任的反馈

在 OpenHarmony 构建的智慧生活生态中,我们应始终铭记:技术的价值,不在于多智能,而在于多有用

这个小小的计价器,正是对这一理念的践行——它不替你花钱,但帮你花得明白。

🌐欢迎加入开源鸿蒙跨平台社区
https://openharmonycrossplatform.csdn.net/

在这里,您将获得:

  • OpenHarmony 生活类应用设计规范;
  • Flutter 列表状态与实时计算模板;
  • 无依赖实用工具开发指南。

用简单,服务日常。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 7:56:30

腾讯混元技术亮点解析:HY-MT1.5-1.8B蒸馏机制详解

腾讯混元技术亮点解析&#xff1a;HY-MT1.5-1.8B蒸馏机制详解 1. 为什么这款翻译模型让人眼前一亮&#xff1f; 你有没有遇到过这样的场景&#xff1a;在海外旅行时&#xff0c;手机拍下菜单却等半天才出译文&#xff1b;或者处理一份带HTML标签的多语技术文档&#xff0c;结…

作者头像 李华
网站建设 2026/4/23 7:49:25

Qwen3-Reranker-8B效果惊艳:数学证明文本→相似解题思路重排序

Qwen3-Reranker-8B效果惊艳&#xff1a;数学证明文本→相似解题思路重排序 1. 这不是普通排序器&#xff1a;它能读懂数学证明的“思维路径” 你有没有试过让AI从一堆数学解题答案里&#xff0c;挑出和当前题目最像的那几个思路&#xff1f;不是看关键词匹配&#xff0c;不是…

作者头像 李华
网站建设 2026/4/23 7:49:27

Qwen3-VL-4B Pro实战:电商商品图自动生成描述文案

Qwen3-VL-4B Pro实战&#xff1a;电商商品图自动生成描述文案 1. 为什么电商运营需要“看图说话”的AI&#xff1f; 你有没有遇到过这些场景&#xff1a; 一天上新20款女装&#xff0c;每张主图都要配300字卖点文案&#xff0c;写到凌晨两点&#xff0c;眼睛干涩、思路枯竭&…

作者头像 李华
网站建设 2026/4/23 7:53:02

3个颠覆性突破:maya-glTF插件重构3D模型转换工作流

3个颠覆性突破&#xff1a;maya-glTF插件重构3D模型转换工作流 【免费下载链接】maya-glTF glTF 2.0 exporter for Autodesk Maya 项目地址: https://gitcode.com/gh_mirrors/ma/maya-glTF 在数字孪生、虚拟制片等前沿领域&#xff0c;3D模型格式转换长期面临兼容性差、…

作者头像 李华
网站建设 2026/4/23 7:55:23

阿里达摩院GPEN实战:AI数字美容刀拯救模糊人像照片

阿里达摩院GPEN实战&#xff1a;AI数字美容刀拯救模糊人像照片 1. 这不是放大&#xff0c;是“重生”——GPEN到底在做什么&#xff1f; 你有没有试过翻出十年前的手机自拍&#xff0c;想发朋友圈却尴尬地发现&#xff1a;眼睛糊成一团、睫毛看不见、连嘴角弧度都模模糊糊&am…

作者头像 李华
网站建设 2026/4/23 7:52:44

ChatGLM3-6B问题解决:告别Gradio冲突的Streamlit优化方案

ChatGLM3-6B问题解决&#xff1a;告别Gradio冲突的Streamlit优化方案 1. 为什么你总在Gradio里“踩坑”&#xff1f; 你是不是也经历过这些时刻&#xff1a; 刚装好gradio4.25.0&#xff0c;一跑ChatGLM3就报错AttributeError: ChatGLMTokenizer object has no attribute ap…

作者头像 李华