news 2026/9/4 22:08:20

鸿蒙原生应用实战:四色占比进度条驱动的分类记录页三态操作设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用实战:四色占比进度条驱动的分类记录页三态操作设计

鸿蒙原生应用实战:四色占比进度条驱动的分类记录页三态操作设计

App 15「智能垃圾分类」分类 Tab(Func2Tab),是分类历史记录页。整页用 Header + 4 个胶囊筛选 Tab(全部/已分类/待处理/错误分类)+ 3 栏统计概览 +4 类彩色占比进度条(可回收 30% 蓝/厨余 48% 绿/有害 12% 红/其他 10% 灰)+ 6 条记录时间线(每条记录按状态显示不同操作:待处理→立即分类、错误分类→重新分类、已分类→✓ 已正确分类)组成。本篇基于15-trash-classify/entry/src/main/ets/pages/Func2Tab.ets(约 248 行)逐段拆解,附 4 张实机截图。

一、整体结构:筛选 + 统计 + 占比 + 时间线

Func2Tab 与 App 14 预约页同构(Header + TabBar 固定、Scroll 内容流),但多了"分类占比"模块

build() { Column() { this.Header() this.TabBar() Scroll() { Column({ space: 16 }) { this.StatsOverview() this.CategoryProgress() this.SectionTitle('分类记录') this.RecordTimeline() } .width('100%') .padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad + this.safeBottom + 20 }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width('100%').height('100%').backgroundColor(C.bg) }

4 个模块:StatsOverview(3 栏统计)→CategoryProgress(4 类占比——本页特色)→ SectionTitle('分类记录') → RecordTimeline(6 条时间线)。

与 App 14 预约页的差异:App 14 是"统计 → 时间线"两段,App 15 是"统计 → 占比 → 时间线"三段——多了一层"分类构成分析""占比图"让用户一眼看到"我分类的垃圾都是什么类型",是数据可视化的进阶用法。

项目源码开源:https://gitee.com/codenestFlow/HarmonyOSHub

二、Header + TabBar:4 个胶囊筛选

Header 单行标题"分类记录",TabBar 是 4 个胶囊(全部/已分类/待处理/错误分类):

@Builder 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) } @Builder TabBar() { Row() { ForEach(this.tabs, (t: FilterTab) => { Text(t.label) .fontSize(13) .fontColor(this.activeTab === t.id ? C.primary : C.textSub) .fontWeight(this.activeTab === t.id ? FontWeight.Bold : FontWeight.Normal) .padding({ left: 14, right: 14, top: 8, bottom: 8 }) .backgroundColor(this.activeTab === t.id ? C.primarySoft : 'transparent') .borderRadius(16) .onClick(() => { this.activeTab = t.id; }) }, (t: FilterTab) => t.id.toString()) } .width('100%') .padding({ left: D.pad, right: D.pad, top: 12, bottom: 12 }) .backgroundColor(C.card) }

4 个 Tab 的 id 与状态值绑定(App 14 同款设计):

private tabs: FilterTab[] = [ { id: 0, label: '全部' }, { id: 1, label: '已分类' }, { id: 2, label: '待处理' }, { id: 3, label: '错误分类' } ];

id = status 值:id=1 已分类(records 里 status=1)、id=2 待处理(status=2)、id=3 错误分类(status=3)——筛选逻辑r.status === this.activeTab一行搞定

与 App 14 的差异:App 14 的 Tab 顺序是"全部/待确认/已完成/已取消"(按"待办优先"排列),App 15 是"全部/已分类/待处理/错误分类"(按"数量优先"排列:已分类 302 条最多放第 2)——Tab 顺序反映业务重心

三、StatsOverview:3 栏统计

StatsOverview 与 App 14 同构(3 栏数字 + 标签):

@Builder StatsOverview() { Row() { ForEach(this.stats, (s: StatItem) => { Column({ space: 4 }) { Text(s.value).fontSize(22).fontWeight(FontWeight.Bold).fontColor(C.text) Text(s.label).fontSize(11).fontColor(C.textDim) } .layoutWeight(1) .alignItems(HorizontalAlign.Center) }, (s: StatItem) => s.label) } .width('100%') .padding({ top: 16, bottom: 16 }) .backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }) }

数据总记录 328 / 已分类 302 / 待处理 26。302 + 26 = 328,数据自洽(已分类 + 待处理 = 总记录,错误分类记录在 302 里计数还是单独?demo 里"错误分类"是 status=3,如果算进"已分类"口径有歧义——但 328 = 302 + 26 至少"总 = 已 + 待"成立)。

3 栏同色C.text深色)——"颜色留给状态"原则(占比进度条和状态标签才是彩色的)。

四、CategoryProgress:四色占比进度条(本页特色)

CategoryProgress 是 4 类垃圾的占比进度条,每类一条彩色进度条

@Builder CategoryProgress() { Column({ space: 12 }) { Text('分类占比').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%') Row({ space: 8 }) { Text('♻️ 可回收').fontSize(11).fontColor(C.textDim).width(60) Progress({ value: 30, total: 100 }).color('#3B82F6').backgroundColor(C.cardSoft).layoutWeight(1).height(6) Text('30%').fontSize(11).fontColor(C.textSub) } Row({ space: 8 }) { Text('🍎 厨余').fontSize(11).fontColor(C.textDim).width(60) Progress({ value: 48, total: 100 }).color('#22C55E').backgroundColor(C.cardSoft).layoutWeight(1).height(6) Text('48%').fontSize(11).fontColor(C.textSub) } Row({ space: 8 }) { Text('⚠️ 有害').fontSize(11).fontColor(C.textDim).width(60) Progress({ value: 12, total: 100 }).color('#EF4444').backgroundColor(C.cardSoft).layoutWeight(1).height(6) Text('12%').fontSize(11).fontColor(C.textSub) } Row({ space: 8 }) { Text('🗑️ 其他').fontSize(11).fontColor(C.textDim).width(60) Progress({ value: 10, total: 100 }).color('#9CA3AF').backgroundColor(C.cardSoft).layoutWeight(1).height(6) Text('10%').fontSize(11).fontColor(C.textSub) } } .width('100%') .padding(14) .backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }) }

4.1 4 条进度条的数据

  • 厨余 48%(绿色)——占比最高,符合"厨余垃圾是日常生活产生最多垃圾"的事实
  • 可回收 30%(蓝色)
  • 有害 12%(红色)
  • 其他 10%(灰色)

30 + 48 + 12 + 10 = 100%,数据完美闭合。占比数据有现实依据(厨余最多、有害最少——中国家庭垃圾构成确实如此)。

4.2 四色进度条的实现

Row({ space: 8 }) { Text('♻️ 可回收').fontSize(11).fontColor(C.textDim).width(60) Progress({ value: 30, total: 100 }).color('#3B82F6').backgroundColor(C.cardSoft).layoutWeight(1).height(6) Text('30%').fontSize(11).fontColor(C.textSub) }

每行三要素:左侧"emoji + 分类名"(固定 60vp 宽,四行对齐)、中间Progress.color('#3B82F6')每类颜色写死)、右侧"百分比数字"。

与 App 14 的差异:App 14 是"一组同色进度条",App 15 是"四色进度条"——颜色与分类一一对应(蓝/绿/红/灰),延续首页的四色编码系统。"四色占比图"本质是"堆叠条形图"的横排版——用 4 条独立进度条表达"各部分占总体的比例",比"一个环形图"实现简单得多(不用画弧形),视觉上也清晰。

真实项目可升级为"环形占比图"ProgressType.Circular):

Progress({ value: 48, total: 100, type: ProgressType.Circular }) .color('#22C55E').width(80).height(80)

但 4 个环形图太占空间,"4 条横排进度条"是"构成占比"的最佳空间方案(一个卡片展示 4 类)。

每行的"百分比 + 进度条"双通道(30% 数字 + 蓝色进度条),色弱用户能读数字。

五、RecordTimeline:三态操作时间线

RecordTimeline 是 6 条分类记录的时间线,每条记录按状态显示不同操作

@Builder RecordTimeline() { Column({ space: 0 }) { ForEach(this.filtered(), (r: Record, idx: number) => { Column({ space: 0 }) { if (idx > 0) { Row().width(2).height(12).backgroundColor(C.stroke).margin({ left: 18 }) } Row({ space: 12 }) { Column() { Row() { Text(r.emoji).fontSize(18) } .width(36).height(36) .backgroundColor(r.catColor + '1A').borderRadius(18) .justifyContent(FlexAlign.Center) } .width(36) Column({ space: 8 }) { Row({ space: 8 }) { Text(r.item).fontSize(14).fontWeight(FontWeight.Medium).fontColor(C.text) Text(r.amount).fontSize(11).fontColor(C.textDim) Blank() Text(r.statusText) .fontSize(11).fontColor(r.statusColor) .padding({ left: 8, right: 8, top: 3, bottom: 3 }) .backgroundColor(C.primarySoft).borderRadius(8) } .width('100%') Row({ space: 6 }) { Text(r.category) .fontSize(11).fontColor(r.catColor) .padding({ left: 6, right: 6, top: 2, bottom: 2 }) .backgroundColor(r.catColor + '1A').borderRadius(4) Text(r.date + ' ' + r.time).fontSize(12).fontColor(C.textDim) } if (r.status === 2) { Row({ space: 8 }) { Button('立即分类') .fontSize(12).fontColor('#FFFFFF').backgroundColor(C.primary) .borderRadius(D.rSm).height(30) .onClick(() => { promptAction.showToast({ message: '处理 ' + r.item }); }) Text('待处理').fontSize(11).fontColor(C.warn) } .width('100%') } if (r.status === 3) { Row({ space: 8 }) { Button('重新分类') .fontSize(12).fontColor('#FFFFFF').backgroundColor(C.danger) .borderRadius(D.rSm).height(30) .onClick(() => { promptAction.showToast({ message: '重新分类 ' + r.item }); }) Text('分类有误').fontSize(11).fontColor(C.danger) } .width('100%') } if (r.status === 1) { Text('✓ 已正确分类').fontSize(11).fontColor(C.ok) } } .alignItems(HorizontalAlign.Start).layoutWeight(1) } .width('100%') .padding({ left: 14, right: 14, top: 14, bottom: 14 }) .backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }) } .width('100%') }, (r: Record) => r.id.toString()) } .width('100%') }

5.1 数据模型:分类色 + 状态色双通道

interface Record { id: number; emoji: string; item: string; category: string; catColor: string; date: string; time: string; status: number; statusText: string; statusColor: ResourceColor; amount: string; }

Record 同时携带catColor(分类色)和statusColor(状态色)——两类颜色语义

  • 分类色(catColor):垃圾属于哪类(蓝/红/绿/灰)→ 图标块背景 + 分类标签
  • 状态色(statusColor):记录处理状态(绿已分类/橙待处理/红错误)→ 状态标签

"分类"和"状态"是两个维度,用两套颜色表达,互不干扰——**"多维度信息用多套颜色编码"**是数据可视化的关键。

5.2 双标签设计

Text(r.category) .fontSize(11).fontColor(r.catColor) .padding({ left: 6, right: 6, top: 2, bottom: 2 }) .backgroundColor(r.catColor + '1A').borderRadius(4) Text(r.date + ' ' + r.time).fontSize(12).fontColor(C.textDim)

一行两个标签:左侧"分类标签"(catColor文字 +catColor + '1A'同色浅底,如蓝字淡蓝底"可回收物")+ 右侧日期时间。分类标签让用户不用点进详情就知道"这是什么类型的垃圾"

5.3 三态操作区

if (r.status === 2) { Row({ space: 8 }) { Button('立即分类') .fontSize(12).fontColor('#FFFFFF').backgroundColor(C.primary) .borderRadius(D.rSm).height(30) .onClick(() => { promptAction.showToast({ message: '处理 ' + r.item }); }) Text('待处理').fontSize(11).fontColor(C.warn) } .width('100%') } if (r.status === 3) { Row({ space: 8 }) { Button('重新分类') .fontSize(12).fontColor('#FFFFFF').backgroundColor(C.danger) .borderRadius(D.rSm).height(30) .onClick(() => { promptAction.showToast({ message: '重新分类 ' + r.item }); }) Text('分类有误').fontSize(11).fontColor(C.danger) } .width('100%') } if (r.status === 1) { Text('✓ 已正确分类').fontSize(11).fontColor(C.ok) }

3 个状态分支,3 种操作

状态按钮颜色右侧文字
待处理(status=2)立即分类绿(C.primary)"待处理" 橙
错误分类(status=3)重新分类红(C.danger)"分类有误" 红
已分类(status=1)无按钮"✓ 已正确分类" 绿

关键差异——"错误分类"的按钮是红色

Button('重新分类') .fontSize(12).fontColor('#FFFFFF').backgroundColor(C.danger)

App 14 预约页的所有操作按钮都是主题绿(C.primary),App 15 的"重新分类"用了危险红——"错误"用红色强化警示(用户看到红按钮知道"这条有问题要处理")。**"操作按钮颜色跟随状态严重性"**是"状态驱动 UI"的进阶——正常操作绿、错误修复红

"✓ 已正确分类"是完成态标识(绿字勾),不需要操作按钮——"无需操作的状态只显示确认信息"

5.4 数据与筛选

filtered()与 App 14 同款(activeTab === 0返回全部,否则filter(status === activeTab))——真筛选。6 条记录:已分类 4 条(废电池/旧报纸/香蕉皮/大骨头)+ 待处理 1 条(塑料瓶)+ 错误分类 1 条(灯泡)——三态都有数据,切换 Tab 能看到不同列表。

6 条记录按日期倒序(08-14 → 08-09),时间线呈现"最近 → 最远"顺序。

六、与 App 14 预约记录页的对比

维度App 14 预约记录App 15 分类记录
Tab待确认/已完成/已取消已分类/待处理/错误分类
统计3 栏3 栏
特色模块四色占比进度条
图标块主题绿(同色)分类色(四色)
分类标签有(分类色标签)
状态按钮取消/再次预约(绿)立即分类(绿)/重新分类(

App 15 的两个进步:① 新增"占比进度条"(构成分析);② 引入"分类色 + 状态色"双色编码系统。"记录列表"模板在系列中不断进化——每次加一个新能力(真筛选→时间线→占比→双色编码)。

七、四色编码系统在记录页的完整应用

App 15 的四色编码系统(蓝可回收/红有害/绿厨余/灰其他)在本页的 4 处应用:

  1. 占比进度条:4 条进度条各用各的颜色
  2. 时间线图标块r.catColor + '1A'同色浅底(废电池🔋红色浅底、旧报纸📰蓝色浅底……)
  3. 分类标签catColor文字 + 同色浅底
  4. (与首页联动):首页入口/指南卡也是四色

"一个颜色系统贯穿全 App"——用户在任何页面看到"蓝色+♻️"就知道是可回收物。"跨页颜色一致性"是品牌识别度的最高形式

实现catColor字段存数据里('#EF4444'红),渲染时r.catColor + '1A'拼浅底。"颜色进数据"让记录页零硬编码

八、扩展建议

  1. 占比图联动筛选:点击"厨余 48%"进度条 → 自动切换到"厨余"筛选(真实项目可实现)
  2. 环形占比图:新增"占比总览"卡片用ProgressType.Circular环形图展示总量构成
  3. 分页加载:328 条记录应分页(.onReachEnd()上滑加载)
  4. 详情页:"立即分类/重新分类"应跳转识别页并预填物品名(跨 Tab 联动)
  5. 删除操作:记录应支持左滑删除(SwipeAction组件)

"记录 + 占比 + 操作"模板可复用到:垃圾分类、记账分类、消费构成、时间统计——任何"按类别记录 + 构成分析 + 状态操作"的场景

九、分类占比的业务价值

"分类占比"模块不只是"好看",它承载 3 层业务价值

1. 反馈层——"我的分类构成"。用户看到"厨余 48%"会想"我厨余垃圾最多,下次多注意可回收"。占比图让用户建立"我每天都在分类什么"的自我认知——这是环保教育的第一步(知道自己分类的对象)。

2. 统计层——"社区/城市的分类结构"。真实项目里,占比数据可以聚合为"全校/全小区分类构成"(厨余 48% 说明该区域餐饮垃圾多),辅助环保部门调整垃圾分类设施(多放厨余桶还是可回收桶)。"个人占比 → 群体占比"是数据产品的增值路径

3. 激励层——"行为引导"。如果"可回收 30%"偏低,App 可提示"回收利用率低于全国平均,试试把纸箱压扁再投递"——"占比 + 建议"驱动行为改变,比单纯记录高级得多。

实现注意:当前占比是硬编码(30/48/12/10),真实项目应从分类记录实时聚合:records.filter(r => r.category === '可回收物').length / records.length * 100——"占比跟着记录走",新增一条记录占比自动更新。**"展示数据永远从业务数据推导"**是数据架构的铁律。

十、时间线的"分类色 + 状态色"双通道无障碍

本页每一条记录同时携带两个颜色维度(分类色 catColor + 状态色 statusColor),这对色弱用户特别重要:

  • 分类信息:图标块背景色(红浅底/蓝浅底…)+ 分类标签文字(红字/蓝字…)——即使分不清红蓝,也能读"有害垃圾""可回收物"文字
  • 状态信息:状态标签文字("待处理"橙/"分类错误"红/"已分类"绿)+ 按钮文案("立即分类""重新分类")——颜色只是辅助,文字才是主通道

"颜色 + 文字双通道"是本系列反复强调的无障碍原则,本页是执行最彻底的:分类、状态、数量、时间全部有文字,颜色只是"锦上添花"的强化。色弱用户(约 8% 人口)不靠颜色也能完整使用本页

对比反例:如果只靠"图标块颜色深浅"区分分类(不写"可回收物"文字),色弱用户就完全无法使用。"先文字后颜色"是数据展示的底线

十一、状态机的"待处理 → 已分类 → 错误分类"流转

本页 3 个状态背后的业务状态机:

新记录 → 待处理 → 已分类(✓ 正确) ↘ 错误分类 → 重新分类 → 已分类
  • 待处理(status=2):AI 识别后待人工确认 → "立即分类"按钮处理
  • 已分类(status=1):人工确认完成 → 显示"✓ 已正确分类"
  • 错误分类(status=3):AI 识别错误 → "重新分类"红色按钮纠错

"待处理 → 立即分类 → 已分类"和"错误分类 → 重新分类 → 已分类"两条路径都通向终态"已分类"——状态机有"汇合"(convergence),是真实业务的常见形态(AI 先识别、人工后确认)。

UI 的操作按钮就是状态机的"事件":立即分类(处理事件)、重新分类(纠错事件)。真实项目应做"状态流转校验":待处理不能直接变错误分类、错误分类不能变待处理——"UI 按钮只是入口,状态机逻辑才是真相"

十二、小结

App 15 分类记录页解析完毕。四色占比进度条(构成分析)+ 分类色/状态色双编码 + 三态操作(绿处理/红纠错/绿确认)+ 状态机流转是四大亮点。

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

用Python模拟二级额外爆率:解析白玉窟钥匙掉落权重

先给结论:二级额外爆率不会改变“白玉窟钥匙”的产物池,它改变的是产物池的抽取权重和是否触发额外抽取的判定。也就是说,它决定的是“这次开钥匙能不能踩中那些稀有物品的额外一层判定”,而不是把池子外面的物品塞进来。 这篇不…

作者头像 李华
网站建设 2026/9/4 21:54:56

先进制造AI+BI落地,为什么要先解决口径不一问题

导语 很多先进制造企业布局AIBI,期望通过智能分析实现生产、供应链、经营等环节的决策提效,但不少项目最终达不到预期效果。核心问题往往不是AI算法能力不足,而是基础数据的口径统一没有解决——AI分析依赖可信的统一口径数据输出&#xff0c…

作者头像 李华
网站建设 2026/9/4 21:53:28

建站公司推荐哪家?模板建站、SaaS建站和定制开发方案对比

建站公司推荐哪家?模板建站、SaaS建站和定制开发方案对比摘要:建站公司推荐哪家,要先看企业真正需要的是模板建站、SaaS建站、AI建站、开源网站服务还是定制开发。不同方案的交付方式、费用结构、维护责任和适用场景差异很大,不能…

作者头像 李华
网站建设 2026/9/4 21:53:16

做小程序找哪家公司更省心?需求梳理、上线审核和售后边界说明

做小程序找哪家公司更省心?需求梳理、上线审核和售后边界说明摘要:做小程序找哪家公司更省心,核心不是谁承诺得更多,而是谁能把需求梳理、微信审核、页面搭建、后台培训和售后边界提前讲清楚。不少企业一开始只问多少钱&#xff0…

作者头像 李华
网站建设 2026/9/4 21:53:08

YOLOv8与度量学习ReID实现跨镜头人脸追踪:从原理到工程实践

简介:本资源是一套基于YOLOv8目标检测与度量学习ReID技术融合实现的跨摄像头人脸连续追踪系统Python源码,面向计算机科学、人工智能、信息安全、大数据等专业的在校学生、教师及企业开发者,解决多视角监控场景下身份中断、遮挡与镜头切换导致…

作者头像 李华
网站建设 2026/9/4 21:51:58

Python处理Excel从入门到实战:读取、匹配与批量合并

这次我们再回到一个很常见的需求:用 Python 处理 Excel 表格。很多做办公自动化的人,一开始想到的都是 Excel 自带的 VBA 宏。VBA 在单文件、单表格里确实够用,但一旦遇到“几十个 Excel 要合并”“每天从系统导出报表后清洗一遍”“要把某个…

作者头像 李华