鸿蒙应用开发之家庭应急物资检查页深度实践:@Builder 三区拆解与状态色编码映射机制
鸿蒙应用开发之家庭应急物资检查页深度实践:@Builder 三区拆解与状态色编码映射机制
文章目录
1、引言
场景是这样的:我们团队最近在开发一款面向家庭用户的应急物资管理应用。产品经理提出了一个极其刚性的诉求——当用户打开"物资检查"页面时,不仅要一眼看到"哪些物资出了问题"的汇总数据(已过期几件、即将过期几件、库存不足几件),还需要在同一个屏幕上,逐条列出每件问题物资的明细,并给出"去补充"的处理入口。
在传统的移动端开发中,这种"告警总览 + 处理列表"的组合布局,往往需要用 Fragment 嵌套 RecyclerView,或者用多个自定义 View 拼装。状态色编码(红色已过期、橙色即将过期、橙色库存不足)散落在 Adapter 的 ViewHolder 里,维护起来极其痛苦——改一个颜色要翻三个文件。
幸运的是,在 HarmonyOS 的 ArkUI 声明式开发范式中,@Builder 装饰器给了我们一种极其优雅的方案:将页面拆分为三个独立的构建块(Header、SummaryCard、CheckList),每个块内部用 ForEach 驱动数据渲染,状态色通过数据模型的 color 字段动态注入,整页代码不到 100 行。
这篇实战手记,我们将从 emergency-kit/entry/src/main/ets/pages/Func2Tab.ets(共 97 行)切入,不仅教你如何用 @Builder 拆解检查页的三区结构,更重要的是,借此机会彻底拆解状态色编码在图标底、问题文字、类型标签三处的贯穿设计,以及告警卡计数与列表条数的数据自洽闭环。我们不背文档,不讲空话,直接看真实场景下的解法。
2、效果展示与页面结构
在正式深入代码之前,我们先看看最终的页面表现和工程底座。直观的视觉冲击能让你瞬间明白我们在解决什么问题。
检查页是"告警总览 + 处理列表"的组合布局,整体由 3 个 @Builder 块构成:
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 14 }) {
this.SummaryCard()
this.SectionTitle('需要处理')
this.CheckList()
}
.width('100%')
.padding({ left: D.pad, right: D.pad, top: 14, bottom: D.pad + this.safeBottom + 20 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
}
.width('100%').height('100%').backgroundColor(C.bg)
}
这个结构的设计初衷是明确划分"总览"和"处理"的职责边界:
- Header — 单行品牌头(“物资检查”),白底固定,20 号加粗,点明本页职能
- SummaryCard — 橙棕渐变三列告警卡(已过期 / 即将过期 / 库存不足),24 号加粗白字
- CheckList — "需要处理"标题 + 4 条检查列表,每条含状态色图标、问题文字、"去补充"按钮
检查页回答的核心问题是"哪些物资有问题、怎么处理"——告警卡给结论(1 过期 / 1 临期 / 2 不足),列表给明细(4 条问题 + 去补充按钮),一页完成"发现问题 → 处理问题"的闭环。

3、Header:单行品牌头的标准范式
Header() {
Row() { Text('物资检查').fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) }
.width('100%').height(this.safeTop + 56).padding({ top: this.safeTop, left: D.pad, right: D.pad })
.backgroundColor(C.card).alignItems(VerticalAlign.Bottom)
}
功能页 Header 的标准范式:20 号字号、固定高度(安全区 + 56vp)、文字贴底对齐。与物资页、我的页同款——品牌一致性是系列应用的基本素养。
这里有一个极其关键的细节:height(this.safeTop + 56) 将状态栏安全区纳入 Header 高度,padding({ top: this.safeTop }) 把文字推到安全区之下。如果不做这层处理,在刘海屏设备上"物资检查"四个字会被状态栏遮挡——这是鸿蒙开发中最容易忽略的适配坑之一。
4、SummaryCard:三列告警渐变卡
SummaryCard() {
Row() {
Column({ space: 4 }) {
Text('1').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('已过期').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
Column({ space: 4 }) {
Text('1').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('即将过期').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
Column({ space: 4 }) {
Text('2').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('库存不足').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
}
.width('100%').padding(20).borderRadius(D.rLg)
.linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}
技术拆解:
第一,橙棕渐变的品牌统一。linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })——从 #D35400 渐变到 #E88050,135 度对角线方向。这与首页准备度卡同款渐变,告警卡不是独立组件,而是品牌视觉体系的一环。用户看到橙棕渐变就联想到"应急物资",这是色彩品牌化的设计目标。
第二,三列均分的布局策略。Row + 三个 layoutWeight(1) Column 实现 1:1:1 等分。每列结构完全一致:24 号 Bold 白字数值 + 12 号 90% 透明度白字标签。数值大、标签小的字号对比,让用户扫一眼就能抓到关键数字(1/1/2),而不需要逐列阅读。
第三,三态告警的分类逻辑。三类问题(已过期 / 即将过期 / 库存不足)各占一列——这与 App 58 首页的三态(正常 / 临期 / 超期)不同,本页三列是"三类问题数量"的聚合统计,按问题类型而非物资状态分列。已过期是效期维度,库存不足是数量维度,两个维度的问题聚合在同一张卡上,因为对用户而言它们都是"需要处理的物资问题"。
第四,数据自洽的计数对账。1 + 1 + 2 = 4 条,恰好等于下方"需要处理"列表的 4 条——告警卡计数 = 列表条数。已过期 1 条(感冒药)、即将过期 1 条(午餐肉)、库存不足 2 条(罐头 + 急救包)。这个对账关系不是巧合,而是数据模型的设计约束:告警卡从同一份 items 数组统计,列表从同一份数组渲染,同源数据保证计数永远一致。
5、CheckList:状态色编码与去补充列表
CheckList() {
Column({ space: 10 }) {
ForEach(this.items, (it: CheckItem) => {
Row({ space: 12 }) {
Row() { Text(it.emoji).fontSize(24) }
.width(48).height(48).backgroundColor(it.color + '22').borderRadius(D.rSm).justifyContent(FlexAlign.Center)
Column({ space: 4 }) {
Text(it.name).fontSize(14).fontWeight(FontWeight.Medium).fontColor(C.text)
Text(it.issue).fontSize(12).fontColor(it.color)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
Text('去补充').fontSize(11).fontColor('#FFFFFF')
.padding({ left: 12, right: 12, top: 6, bottom: 6 }).backgroundColor(C.primary).borderRadius(D.rSm)
.onClick(() => { promptAction.showToast({ message: '采购 ' + it.name }); })
}
.width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke })
}, (it: CheckItem) => it.id.toString())
}.width('100%')
}
4 条检查数据(21-26 行):
| 物资 | 问题 | 类型 | 颜色 |
|---|---|---|---|
| 🥫 午餐肉罐头 | 将于 2026-09 过期 | 即将过期 | 橙 |
| 💊 感冒药 | 已于 2026-07 过期 | 已过期 | 红 |
| 🥫 罐头食品 | 库存仅剩 6 件 | 库存不足 | 橙 |
| 🩹 医药急救包 | 库存仅剩 1 个 | 库存不足 | 橙 |
这段代码中有几处极其精妙的设计,是我们在多次迭代后沉淀出来的:
第一,状态色透明底图标的颜色编码。backgroundColor(it.color + '22')——将状态色十六进制值拼接 '22'(13% 透明度)作为图标容器背景。过期物资的图标底是红色透明(#FF5A6E22),不足物资的图标底是橙色透明(#FF9F1C22)。图标底随问题类型变色,而非统一用主题色——这是检查页与首页的关键差异。首页的图标底用主题色软底(品牌统一),检查页的图标底用问题色(问题导向),强化"这条有问题"的视觉信号。
第二,问题文字的状态色注入。Text(it.issue).fontSize(12).fontColor(it.color)——问题描述文字直接使用状态色。"将于 2026-09 过期"显示为橙色,"已于 2026-07 过期"显示为红色。文字颜色编码问题严重度:红色 = 已不能使用(最紧急),橙色 = 快到期限或快用完(次紧急)。用户扫列表时,红色文字最先被注意,优先处理。
第三,"去补充"按钮的行动导向。右侧橙色实心小按钮(C.primary 底 + 白字 + 圆角 + padding 12×6),点击弹 Toast"采购 午餐肉罐头"。这是检查页的核心交互——不只是"发现问题",还"给出动作"。过期物资"去补充"是买新的(旧的丢弃),不足物资"去补充"是补数量(6 → 12),即将过期物资"去补充"是提前补新货。三类问题的处理动作统一收敛为"去补充"一个入口,减少操作路径。
第四,状态色在三处的贯穿编码。同一状态色出现在三个位置:图标底(状态色 13% 透明)、问题文字(状态色实色)、类型标签(即将过期 / 已过期 / 库存不足)。三处同色系强化"这条有问题"的认知——图标底给"全局色感"、文字给"具体问题"、标签给"分类归属",同一颜色编码三处呈现,用户扫一眼就能判断"哪类问题、多严重"。

6、跨页数据自洽:物资检查的全局闭环
检查页不是孤岛——它与首页、物资页、我的页形成四页数据闭环:
- 检查页"1 已过期(感冒药)" ↔ 我的页"过期提醒"开关——感冒药已于 2026-07 过期,触发我的页"过期提醒"推送(开关开启时),过期检查 → 过期提醒。
- 检查页"午餐肉 2026-09 即将过期" ↔ 物资页"罐头"——午餐肉罐头是物资页"食品饮水"分类下的物品,保质期临近,库存管理 → 效期检查。
- 检查页"罐头食品 库存仅剩 6 件" ↔ 首页"罐头食品 偏少 6 件"、物资页"罐头 6"——数量完全一致(6 件),首页标"偏少"、检查页标"库存不足"(更紧急)、物资页可 + 补货,三页同一库存状态机。
- 检查页"医药急救包 库存仅剩 1 个" ↔ 首页"医药急救包 偏少 1 件"——数量一致(1 件),急救包是最关键应急物资(伤病急救),库存不足最需优先处理。
- 检查页"2 库存不足" ↔ 首页"2 项物资需要补充"——数量一致(2 项),首页准备度卡的待补量 = 检查页库存不足数,首页缺口 → 检查页处理。
这套闭环的核心是统一数据源——四页共享同一份物资数据模型,首页做"准备度总览"、物资页做"库存管理"、检查页做"问题处理"、我的页做"提醒配置",各司其职但数据同源。改一处库存,四页同步刷新。
7、多维度方案选型对比:检查处理页的三种形态
在实际的架构研讨中,有同学曾经发出过极其尖锐的质疑:“检查页为什么不直接用首页的’偏少列表’?为什么要单独做一个检查页?”
为了彻底解答这个选型问题,我们将系列中"检查 / 处理"型页面对比:
| 维度 | App 60 检查页 | App 58 日志页 | App 53 保修页 | App 56 费用页 |
|---|---|---|---|---|
| 核心定位 | 问题处理 | 历史沉淀 | 信息查询 | 数据统计 |
| 顶部卡片 | 三列告警渐变卡 | 统计卡 | 保修卡 | 月度卡 + 柱状图 |
| 列表内容 | 4 条问题 + 去补充按钮 | 时间轴记录 | 售后电话 | 费用明细 |
| 处理动作 | 有(去补充) | 无 | 有(呼叫) | 无 |
| 状态色编码 | 红 / 橙三态 | 无 | 无 | 无 |
60 的差异化在于**“去补充"处理按钮**——检查列表每条带橙色"去补充"按钮,是"检查 → 处理"的行动闭环。其他检查 / 统计页多为只读展示(日志页看历史、费用页看数据),而检查页不只是"发现问题”(告警卡)还"给出动作"(去补充按钮)。过期与不足都通过"去补充"解决(补新 / 补量),"发现问题 → 立即处理"的行动导向是应急场景的核心——物资问题不能拖。
8、避坑指南:检查页的四个防翻车细节
在将这套看起来优雅的检查页设计推向真实生产环境时,我们踩过了几个深浅不一的暗坑。以下是内部复盘后沉淀的防翻车铁律:
第一,过期判定必须动态化。“将于 2026-09 过期 / 已于 2026-07 过期"在演示中是写死文案——产品化必须由"当前日期 vs 有效期"动态判定。30 天内过期 = 即将过期、已过有效期 = 已过期。日期推进后状态自动变化(2026-09 到了,午餐肉从"即将过期"变"已过期”),检查列表实时刷新。如果写死文案,应用上线一个月后所有"即将过期"都变成了"已过期"但界面不更新,用户会完全失去信任。
第二,库存不足判定与首页联动。库存不足(罐头 6 / 急救包 1)与首页"偏少"是同一库存——产品化必须统一状态机。建议阈值:库存 ≤ 建议量 50% 标"偏少"(首页)、≤ 20% 标"库存不足"(检查页)。物资页加减后首页与检查页同步刷新,避免"首页偏少、检查页不足"阈值不一致导致用户困惑。
第三,去补充的动作闭环。"去补充"只弹 Toast 是演示级别——产品化必须接入采购流程。点击"去补充"跳采购页 / 加购物清单 / 记录采购,采购后库存更新(罐头 6 → 12)、检查列表移除该条、首页状态刷新(偏少 → 充足)。"去补充 → 采购 → 库存更新 → 问题解决"的完整闭环,否则用户点了按钮但问题没解决,检查页就成了"只报问题不解决问题"的摆设。
第四,图标底的问题色辨识度。it.color + '22' 状态色透明底在浅色 emoji 上对比清晰,但若物资图标是深色 emoji(🔦 手电)叠加红色底,辨识度可能下降。产品化可加"状态圆点"或"问题文字加粗"辅助,确保状态色在任何图标上都可辨识。另外,检查列表的排序应按紧急度——已过期(红)置顶 > 即将过期(橙)> 库存不足(橙),让"最紧急的问题"排在最上,用户打开检查页先看到红色已过期项优先处理。

9、常见问题 FAQ
问:检查页的 4 条问题是从哪来的?
答:演示数据设定 4 条待处理——午餐肉即将过期(2026-09)、感冒药已过期(2026-07)、罐头食品库存不足(6 件)、医药急救包库存不足(1 件),分别对应三类告警(即将过期 1、已过期 1、库存不足 2)。产品化后由物资数据动态生成:遍历所有物资,判断效期与库存生成检查项,新增物资 / 库存变化后自动更新。
问:为什么感冒药"已过期"是红色而库存不足是橙色?
答:紧急度分级——已过期(感冒药 2026-07)是"现在已经不能用了"(最紧急,红色 danger),即将过期(午餐肉 2026-09)与库存不足(罐头 / 急救包)是"快到了但还有时间"(橙色 warn)。红色 > 橙色的紧急度编码(与 App 53/55 的"超期红 / 临期橙"语义一致),用户扫列表时红色(已过期)最先被注意、优先处理。
问:"去补充"对已过期和库存不足的处理一样吗?
答:动作一样(都是"去补充"按钮)、内容不同——已过期的感冒药"去补充"是买新药(旧的丢弃),库存不足的罐头"去补充"是补数量(6 → 12),即将过期的午餐肉"去补充"是提前补新(旧的尽快吃)。统一用"去补充"入口(产品化后区分"丢弃 + 补充"流程),处理动作收敛为一个按钮减少操作路径。
问:已过期和即将过期有什么区别?
答:时间维度不同——已过期(感冒药 2026-07 已过)是"现在已经不能用了"(过期药必须丢弃,最紧急),即将过期(午餐肉 2026-09 快过)是"还没过期但快到了"(可尽快食用或提前补充,稍缓)。告警卡两列分开计数(1 已过期 / 1 即将过期),列表用红(已过期)/ 橙(即将过期)区分紧急度,红色优先处理。

10、总结
纵观本篇对 emergency-kit 检查页(Func2Tab,97 行)的逐块拆解,@Builder 复用范式绝对不是大家在走马观花浏览 ArkUI 文档时所以为的"仅仅只是把代码拆成几个函数"那么简单。
检查页用三个 @Builder 块完成了"告警总览 + 处理列表"的组合布局:Header 点明职能、SummaryCard 给出问题汇总(1 已过期 / 1 即将过期 / 2 库存不足)、CheckList 给出明细与动作(4 条问题 + 去补充按钮)。整页的视觉语言围绕"状态色 + 行动"展开——红橙状态色编码紧急度、状态色透明图标底强化问题感、"去补充"橙色按钮突出行动,用户一页完成"发现问题 → 处理问题"的闭环。
从演示到产品,检查页的进化方向清晰:定期巡检(每月自动推送巡检结果)、分级处理(按紧急度排序 + 分级提醒)、采购清单联动(一键加入购物清单)、物资健康报告(月度健康报告)。状态色编码与去补充按钮是本页的核心,让应急物资的维护"问题可见、动作可达"。
更多推荐





所有评论(0)