当前位置: 首页 > news >正文

Flutter/HarmonyOS 实战|中式美食买菜清单勾选状态:checkedIds、统计卡与可点击食材条

上一篇写买菜清单页时,重点讲的是“从一桌方案拆出采购分组”。这篇往里再走一步:用户真的开始核对食材时,页面状态应该怎么跟着变。

买菜清单这种页面,最容易被做成静态列表。菜名、数量、备注都摆出来,好像就完成了。但真实使用时,用户需要一边看一边确认:鱼买了没有,排骨买了没有,青菜能不能换,调味料家里有没有。这个时候,勾选状态和进度反馈就很重要。

中式美食当前的做法是:用checkedIds统一记录已确认食材,再让统计卡、食材条和底部动作一起响应这个状态。这样用户看一眼就知道清单还差几项,不用自己在脑子里数。

本文验证环境

项目版本或范围
开发工具Flutter / Dart 工程,配合 DevEco Studio 做 HarmonyOS 上架前体验验证
Dart SDK^3.12.2
Flutter 依赖fluttercupertino_iconsflutter_lints
HarmonyOS 目标中式美食上架后的家庭餐桌链路,HarmonyOS SDK API 20 作为后续适配目标
核心文件lib/main.dart
核心页面ShoppingListPage
核心组件ShoppingSummaryCardShoppingSectionShoppingIngredientSlip
核心状态checkedIds

这里讲的是当前 Flutter 工程里的真实实现。后面如果迁移到 ArkUI,思路仍然一样:一个集合记录已确认项,列表和统计都从这个集合派生。

不要给每个条目单独维护状态

清单页初始化时,会先根据当前餐桌方案生成分组,再把默认已确认的食材放进checkedIds

class_ShoppingListPageStateextendsState<ShoppingListPage>{latefinalList<ShoppingSectionData>sections;latefinalSet<String>checkedIds;@overridevoidinitState(){super.initState();sections=shoppingSectionsFor(widget.plan);checkedIds={for(finalsectioninsections)for(finaliteminsection.items)if(item.checked)item.id,};}}

这个写法的关键是:页面不直接改ShoppingItemData.checked

如果用户点一下就去改数据对象本身,后面会出现两个麻烦。第一,原始清单和当前确认状态混在一起;第二,想重置、保存、对比变化时不好做。用Set<String>存 id 会清爽很多,原始清单还是原始清单,用户当前操作是另一层状态。

这类页面我更喜欢把“数据是什么”和“用户现在点了什么”分开。前者来自方案,后者来自页面交互。

勾选切换要足够简单

toggleItem()的逻辑很直白:

voidtoggleItem(Stringid){setState((){if(!checkedIds.add(id)){checkedIds.remove(id);}});}

Set.add()如果发现 id 已经存在,会返回false。所以这里可以很自然地写成:加不进去就说明已经勾过了,那就移除。

这个逻辑小,但它决定了交互是否稳定。用户连点几次,不会把状态弄乱;列表刷新后,统计也会一起变。

统计卡不要只是装饰

清单页顶部的统计卡会展示总项数和已确认项:

intgettotalItems=>sections.fold(0,(total,section)=>total+section.items.length);ShoppingSummaryCard(totalItems:totalItems,checkedCount:checkedIds.length,)

这里的checkedCount直接来自checkedIds.length,不是另起一个计数器。

这是一个很重要的习惯:能从状态算出来的值,就不要再存一份。否则用户勾选了食材,列表状态变了,但统计数字没变,这种 bug 很难看。

显示项来源作用
食材总类sections汇总告诉用户这次采购复杂度
已确认数量checkedIds.length告诉用户还差多少项
预计采购时间页面配置给用户一个心理预期

统计卡不是为了好看,而是为了让用户知道自己进行到哪了。

食材条要整行可点

移动端上,如果只让用户点一个小圆圈,体验会比较累。中式美食这里把整条食材都做成可点击:

classShoppingIngredientSlipextendsStatelessWidget{constShoppingIngredientSlip({requiredthis.item,requiredthis.checked,requiredthis.onToggle,});finalShoppingItemDataitem;finalbool checked;finalVoidCallbackonToggle;}

真实组件里外层用了InkWell,里面的小勾选圈也能点。这样用户在超市或者厨房里拿着手机,不需要精确点中一个很小的控件,手指点到整行就能切换状态。

这类细节看着不技术,但很影响留存。生活类工具不是给用户演示组件的,用户是在边走边看,甚至手上还拿着东西。交互热区大一点,体验会舒服很多。

备注要跟状态一起读

食材条里除了名称和数量,还有备注:

classShoppingItemData{constShoppingItemData({requiredthis.id,requiredthis.name,requiredthis.amount,this.note,this.checked=false,});finalStringid;finalStringname;finalStringamount;finalString?note;finalbool checked;}

比如“小青菜,可换菜心”。这个备注会影响用户是否勾选:如果现场没有小青菜,但有菜心,用户知道可以替换,就不会停在那里纠结。

所以买菜清单的条目不应该只有name。数量、备注、默认状态都值得放进模型里。后面如果接家庭库存,甚至可以继续加“家里已有”“常买品牌”“预计价格”。

工程验收记录

检查点当前结果
默认勾选initState()根据ShoppingItemData.checked初始化checkedIds
状态切换toggleItem()通过Set增删 id,状态逻辑简单
统计反馈ShoppingSummaryCard使用checkedIds.length展示已确认数量
整行点击ShoppingIngredientSlip外层可点击,小勾选圈也可点击
数据边界原始食材数据和用户当前勾选状态分开
后续扩展可以继续接家庭库存、替换建议、价格估算

本文小结

买菜清单的价值不只是列出食材,而是帮用户把“我确认了什么、还差什么”看清楚。

中式美食这里用checkedIds管住勾选状态,用统计卡反馈进度,再把整行食材做成可点击。这个实现不花哨,但很适合家庭餐食场景:用户在买菜时不想研究页面,只想快速确认下一项。

如果你也在做清单类页面,我建议先把两个问题想清楚:状态是不是只有一个来源?用户是不是能不用精确点击也完成操作?这两个点做好,页面会比单纯堆视觉组件更耐用。

最后留个具体问题:如果买菜清单支持多人协作,你会把checkedIds做成本地状态同步,还是直接把每个食材的确认状态写进远端记录?我会先本地跑顺,再把状态同步抽出去。

http://www.jsqmd.com/news/1149895/

相关文章:

  • Cuppa CMS 文件包含漏洞实战:W1R3S 1.0.1靶机从LFI到Root的3步提权
  • HackMe-1 靶机实战:SQL注入到文件上传的 3 步完整攻击链复现
  • 高效太阳能电池缺陷检测基准:2624张EL图像深度学习实战指南
  • 010Editor 网络验证绕过实战:3 种补丁方法与 1 个关键跳转定位
  • Burp Suite 2024.6 实战:3类业务逻辑漏洞靶场复现与自动化脚本编写
  • iwebsec靶场 XXE漏洞实战:3种协议读取文件与内网探测(附完整Payload)
  • B/S架构电子病历编辑器(EMRE)部署实战:SpringBoot 2.7 + MySQL 8.0 环境搭建5步
  • A3910与MKV58F1M0VLQ24在工业电机控制中的经典组合
  • 微信小程序内容安全审核 2.0:imgSecCheck 与 mediaCheckAsync 双接口选型指南
  • 语音克隆实战终极指南:10分钟数据训练高质量变声模型
  • 基于51/STM32单片机矿井安全 瓦斯检测 天然气 甲烷报警物联网31(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 5个步骤轻松解锁加密音乐文件:Unlock Music完全使用指南
  • 云注入去除方案对比:算法助手 vs MT解密工具 vs 手动Smali修改
  • 从零开始:STM32温度控制系统的实战指南
  • iwebsec靶场 XXE漏洞实战:3种协议读取/etc/passwd与源码(附PHP/Java/Python防御代码)
  • DVWA DOM XSS 4级漏洞实战:从Low到Impossible的3种绕过与1个防御核心
  • BQ25887充电芯片与TM4C129ENCPDT的电池平衡系统设计
  • 基于Arduino单片机温湿度报警 大棚温湿度采集系统 DHT1131(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • Spring Boot + Vue 前后端分离订餐系统:5个常见安全漏洞与JWT认证方案
  • Citrix DDC 与 vCenter 证书信任:2种证书获取方法对比与“受信任的人”存储安装要点
  • Java RMI反序列化漏洞实战:ysoserial工具链利用与3种防护策略
  • 【Springboot毕设全套源码+文档】基于SpringBoot的吉他谱分享平台的设计与实现(丰富项目+远程调试+讲解+定制)
  • Unlock Music终极指南:3步解锁加密音乐,重获数字音乐所有权
  • XSS-Platform 源码部署实战:PHP 7.4 + Apache 环境 5 步配置避坑指南
  • PIC18F47Q10与PAM8904构建高效嵌入式警报系统
  • App安全测试自动化:3款开源工具对比与CI/CD集成实战
  • OWASP ZAP 2.15 与 Burp Suite 2024 对比评测:5 大核心功能与实战效率分析
  • 探索式测试(ET)与脚本测试(ST)实战对比:3个真实场景下的效率与缺陷发现率分析
  • Burp Suite CO2 1.2.0 插件实战:5步集成SQLMap自动化SQL注入检测
  • CVE-2023-33246 Apache RocketMQ 5.1.0 漏洞深度剖析:从配置更新到命令注入的3层调用链