鸿蒙原生应用实战:HarmonyOS 6.0 垃圾分类我的页 —— 签到联动经验条的环保中心
鸿蒙原生应用实战:HarmonyOS 6.0 垃圾分类我的页 —— 签到联动经验条的环保中心
App 15「智能垃圾分类」我的 Tab(ProfileTab),是个人中心页。整页用渐变用户卡片(李环保 + Lv.6 + 1860/3000 经验条 + 可交互签到)+ 4 栏统计(分类/准确率/减碳/等级)+ 3 列环保成就墙(6 徽章 4 解锁)+ 本周分类次数条形图(总计 47 次)+ 6 项菜单(分类日历带数字 3/NEW 角标)+ AboutInfo 组成。本篇基于
15-trash-classify/entry/src/main/ets/pages/ProfileTab.ets(约 312 行)逐段拆解,附 4 张实机截图。
一、整体结构:与 App 14 同源的绿色个人中心
ProfileTab 与 App 14 我的页几乎同构(6 个 @Builder 块、同样的布局顺序),差异在数据和文案:
build() {
Column() {
Scroll() {
Column({ space: 14 }) {
this.UserCard()
this.StatRow()
this.AchievementWall()
this.WeeklyChart()
this.MenuList()
this.AboutInfo()
}
.width('100%')
.padding({ left: D.pad, right: D.pad, bottom: D.pad + this.safeBottom + 20 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
}
.width('100%').height('100%').backgroundColor(C.bg)
}
6 个块顺序:UserCard(身份)→ StatRow(数据)→ AchievementWall(成就)→ WeeklyChart(行为图)→ MenuList(资产)→ AboutInfo(关于)。
与 App 14 我的页对比:
| 维度 | App 14 运动 | App 15 环保 |
|---|---|---|
| 主题色 | 绿 #16A34A | 绿 #22C55E |
| 用户 | 张运动 Lv.5 | 李环保 Lv.6 |
| 经验 | 1280/2000(64%) | 1860/3000(62%) |
| 统计 | 预约/时长/场地/卡路里 | 分类/准确率/减碳/等级 |
| 成就 | 篮球/足球/羽毛球… | 环保新手/回收达人/减碳先锋… |
| 签到 | +10 积分 | +5 环保积分 |
| 周图 | 运动时长 7.5h | 分类次数 47 次 |
"同一套个人中心模板,换主题换数据"——系列化 demo 的复用方法论在"我的页"上体现得最彻底(App 13/14/15 三连复用)。

二、UserCard:Lv.6 经验条 + 可交互签到
UserCard 与 App 14 同构(渐变用户卡),差异在数据:
@Builder
UserCard() {
Column({ space: 12 }) {
Row({ space: 14 }) {
Row() {
Text('🌿').fontSize(32)
}
.width(60).height(60)
.backgroundColor('#FFFFFF').opacity(0.3).borderRadius(30)
.justifyContent(FlexAlign.Center)
Column({ space: 4 }) {
Row({ space: 8 }) {
Text('李环保').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Row() {
Text('Lv.6').fontSize(10).fontColor('#FFFFFF')
}
.padding({ left: 8, right: 8, top: 3, bottom: 3 })
.backgroundColor('#FFFFFF').opacity(0.25).borderRadius(8)
}
Text('环保达人 · 减碳 15.6kg').fontSize(12).fontColor('#FFFFFF').opacity(0.85)
}
.alignItems(HorizontalAlign.Start).layoutWeight(1)
Text('编辑').fontSize(12).fontColor('#FFFFFF').opacity(0.85)
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.border({ width: 1, color: '#FFFFFF' }).borderRadius(D.rSm)
.onClick(() => { promptAction.showToast({ message: '编辑资料' }); })
}
.width('100%')
Column({ space: 4 }) {
Row() {
Text('经验值').fontSize(11).fontColor('#FFFFFF').opacity(0.85)
Blank()
Text('1860 / 3000').fontSize(11).fontColor('#FFFFFF').opacity(0.85)
}
.width('100%')
Progress({ value: 62, total: 100 })
.color('#FFFFFF').backgroundColor('#33FFFFFF')
.height(6).borderRadius(3).width('100%')
}
.width('100%')
Row() {
Text(this.checked ? '✓ 今日已签到' : '每日签到 +5 环保积分')
.fontSize(13).fontColor('#FFFFFF')
.layoutWeight(1)
Text(this.checked ? '已签到' : '签到')
.fontSize(13).fontColor(C.primary)
.padding({ left: 16, right: 16, top: 6, bottom: 6 })
.backgroundColor('#FFFFFF').borderRadius(D.rSm)
.onClick(() => {
if (!this.checked) {
this.checked = true;
promptAction.showToast({ message: '签到成功 +5 积分' });
}
})
}
.width('100%')
.padding({ left: 12, right: 12, top: 10, bottom: 10 })
.backgroundColor('#33FFFFFF').borderRadius(D.rSm)
}
.width('100%')
.padding(16)
.borderRadius(D.rLg)
.linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}
2.1 用户数据与品牌调性
- 头像:🌿(环保叶)——呼应"绿色环保"主题
- 姓名:"李环保"——姓名带产品属性(环保),比"小明/张运动"更贴 App 调性
- 等级:Lv.6(系列最高)——用户越老练,与 App 13 的 Lv.4、App 14 的 Lv.5 形成"递进"
- Slogan:"环保达人 · 减碳 15.6kg"——减碳量直接进 Slogan,把环保成果变成身份标签
经验条 1860/3000(62%):比 App 14 的 1280/2000 更高——等级越高、经验越多,数据一致(Lv.6 对应更多累计经验)。
2.2 签到 +5 环保积分
签到逻辑与 App 14 完全同构(@State checked + if (!this.checked) 防重复):
.onClick(() => {
if (!this.checked) {
this.checked = true;
promptAction.showToast({ message: '签到成功 +5 积分' });
}
})
差异在积分值:App 14 是 +10 运动积分,App 15 是 +5 环保积分——"积分值"是产品设计参数(环保场景每日 +5 更合理,运动场景 +10 更有激励感)。同一个交互模板,不同业务参数——模板复用的完美示例。

三、StatRow:4 栏统计(含等级)
StatRow 与 App 14 同构(负边距悬浮卡),但统计项包含"等级":
private stats: StatItem[] = [
{ value: '328', label: '分类' },
{ value: '92%', label: '准确率' },
{ value: '15.6kg', label: '减碳' },
{ value: 'Lv.6', label: '等级' }
];
4 栏统计:分类 328 / 准确率 92% / 减碳 15.6kg / 等级 Lv.6——与首页 HeroCard 三栏(328/92%/15.6kg)完全一致,多了"等级"维度。跨页数据一致(首页/记录页/我的页三个页面共用 328/92%/15.6kg 数据)。
"等级"作为统计项是 App 15 的特色——前两代(App 13/14)的统计都是"行为数据"(订单/预约),App 15 加"身份数据"(Lv.6)——"行为 + 身份"混合统计反映"环保等级是用户最在意的身份标签"。
margin({ top: -28 }) 负边距悬浮 + 4 栏同色(C.text)——与 App 14 同款。
四、AchievementWall:环保主题成就墙
AchievementWall 是 6 个环保徽章的 3 列 Grid(4 解锁 2 未解锁):
@Builder
AchievementWall() {
Column({ space: 12 }) {
Row() {
Text('成就墙').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text)
Blank()
Text('4/6').fontSize(12).fontColor(C.textDim)
}
.width('100%')
Grid() {
ForEach(this.badges, (b: Badge) => {
GridItem() {
Column({ space: 6 }) {
Row() {
Text(b.emoji).fontSize(24)
}
.width(48).height(48)
.backgroundColor(b.unlocked ? C.primarySoft : C.cardSoft)
.borderRadius(24)
.justifyContent(FlexAlign.Center)
.opacity(b.unlocked ? 1.0 : 0.4)
Text(b.name).fontSize(10).fontColor(b.unlocked ? C.text : C.textDim)
}
.alignItems(HorizontalAlign.Center)
}
}, (b: Badge) => b.id.toString())
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
}
.width('100%')
.padding(14)
.backgroundColor(C.card).borderRadius(D.rMd)
.border({ width: 1, color: C.stroke })
}
6 个环保徽章(数据):
private badges: Badge[] = [
{ id: 1, emoji: '🌱', name: '环保新手', unlocked: true },
{ id: 2, emoji: '♻️', name: '回收达人', unlocked: true },
{ id: 3, emoji: '🌍', name: '减碳先锋', unlocked: true },
{ id: 4, emoji: '📚', name: '知识百科', unlocked: true },
{ id: 5, emoji: '🏆', name: '分类王者', unlocked: false },
{ id: 6, emoji: '🥇', name: '环保大使', unlocked: false }
];
徽章名有"成长阶梯":
- 入门级(已解锁):环保新手 🌱 → 回收达人 ♻️ → 减碳先锋 🌍 → 知识百科 📚
- 高级目标(未解锁):分类王者 🏆 → 环保大使 🥇
"新手→达人→先锋→百科→王者→大使"的等级叙事——每个徽章名都体现"环保能力等级",用户有清晰的成长路径。
解锁/未解锁三件套(背景/透明度/文字)与 App 14 同款。4/6 硬编码(App 13 用 .filter() 动态算,App 14/15 都硬编码——"动态计算 vs 硬编码"的取舍,真实项目建议动态)。
五、WeeklyChart:本周分类次数
WeeklyChart 与首页同构(7 天条形图),汇总改为"总计 47 次":
@Builder
WeeklyChart() {
Column({ space: 12 }) {
Row() {
Text('本周分类次数').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text)
Blank()
Text('总计 47 次').fontSize(12).fontColor(C.primary)
}
.width('100%')
Row({ space: 4 }) {
ForEach(this.barData, (b: BarItem) => {
Column({ space: 6 }) {
Stack({ alignContent: Alignment.Bottom }) {
Column()
.width(18).height(b.value)
.linearGradient({ angle: 180, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
.borderRadius(4)
}
.width(24).height(90)
Text(b.day).fontSize(10).fontColor(C.textDim)
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Center)
}, (b: BarItem) => b.day)
}
.width('100%')
}
.width('100%')
.padding(14)
.backgroundColor(C.card).borderRadius(D.rMd)
.border({ width: 1, color: C.stroke })
}
"总计 47 次"的数据推导:barData 是 50/70/45/85/60/90/75(百分比强度),如果按"每天分类次数 ≈ 强度/2"换算:25+35+22+42+30+45+37 ≈ 236 次/周?不对——demo 显示"47 次",是另一套口径(可能是"本周实际记录 47 次")。注意这里的"数据口径不一致":首页趋势图是"强度百分比"(平均 68%),我的页是"次数"(47 次)——同一天的数据,两个页面两个度量。真实项目应统一口径(要么都显示次数,要么都显示百分比),这是 demo 的"数据瑕疵",也值得写出来提醒读者。
图表本身(Stack 底部对齐 + 渐变绿 + 7 天)与首页/App 14 完全同构。
六、MenuList:6 项菜单 + 数字/NEW 角标
MenuList 与 App 14 同构(6 项菜单 + 两种角标),数据换成环保主题:
private menus: MenuItem[] = [
{ id: 1, emoji: '📅', label: '分类日历', desc: '查看每日分类记录', badge: '3' },
{ id: 2, emoji: '👥', label: '邀请好友', desc: '一起参与环保', badge: '' },
{ id: 3, emoji: '⭐', label: '我的收藏', desc: '收藏的分类知识', badge: '' },
{ id: 4, emoji: '🎁', label: '积分兑换', desc: '环保积分换好礼', badge: 'NEW' },
{ id: 5, emoji: '⚙️', label: '提醒设置', desc: '定时分类提醒', badge: '' },
{ id: 6, emoji: '💬', label: '意见反馈', desc: '帮助与反馈', badge: '' }
];
角标编排:
- 📅 分类日历 — badge "3"(3 条待处理记录,呼应分类页统计"待处理 26"?——demo 数字不完全一致,但"分类日历有内容待看"的语义成立)
- 🎁 积分兑换 — badge "NEW"(新功能引导)
数字角标(3)和 NEW 角标的两种形态(圆形/胶囊)与 App 14 完全同构:
if (m.badge === 'NEW') {
Text(m.badge).fontSize(9).fontColor('#FFFFFF')
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.backgroundColor(C.danger).borderRadius(4)
} else {
Text(m.badge).fontSize(9).fontColor('#FFFFFF')
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.backgroundColor(C.danger).borderRadius(9)
.constraintSize({ minWidth: 18 }).textAlign(TextAlign.Center)
}
constraintSize({ minWidth: 18 }) + textAlign(Center) + borderRadius(9)——数字徽标的"正圆"三件套(1 位数正圆、2 位数椭圆)。
菜单语义与环保主题:"邀请好友(一起参与环保)""积分兑换(环保积分换好礼)""定时分类提醒"——每个菜单项都带环保业务语义,不是通用菜单模板。
七、AboutInfo:版本信息
AboutInfo 与 App 14 同构(版本 + 技术栈 + 版权三行):
@Builder
AboutInfo() {
Column({ space: 6 }) {
Text('智能垃圾分类 v1.0.0').fontSize(12).fontColor(C.textDim)
Text('基于 HarmonyOS 6.0+ ArkTS 开发').fontSize(11).fontColor(C.textDim)
Text('© 2024 智慧校园').fontSize(10).fontColor(C.textDim).opacity(0.6)
}
.width('100%')
.padding({ top: 16, bottom: 16 })
.alignItems(HorizontalAlign.Center)
}
"智能垃圾分类 v1.0.0"——App 名随产品变化(运动场地预约 v1.0.0 → 智能垃圾分类 v1.0.0),模板参数化。
八、@State 的克制
ProfileTab 只有 1 个 @State:checked: boolean(签到状态)——与 App 14 完全一致("展示页 1 个 @State"是本系列的我的页标准)。
4 个 Tab 的 @State 分布:
| 页面 | @State 数量 | 类型 |
|---|---|---|
| 首页 HomeTab | 1(keyword) | 展示+搜索 |
| 识别 Func1Tab | 6(keyword/selectedCat/result/resultCat/resultColor/note) | 交互查询 |
| 分类 Func2Tab | 1(activeTab) | 筛选 |
| 我的 ProfileTab | 1(checked) | 展示+签到 |
识别页 6 个 @State 是 4 页最多——它承载"搜索 + 选择 + 预览 + 提交"最复杂的交互;其他 3 页各 1 个(展示/筛选/签到)。**"@State 数量 = 页面交互复杂度"**再次得到验证。
九、游戏化闭环:环保版
App 15 我的页的游戏化链路(环保版):
- 签到 +5 环保积分(每日激励)→
checked翻转 - 经验条 1860/3000(62%)(长期目标)→ 还差 1140 经验
- 成就墙 4/6(身份认同)→ 环保新手→回收达人→减碳先锋→知识百科
- Lv.6 徽章(等级象征)→ 系列最高等级
与 App 13/14 的游戏化对比:
| App | 签到 | 积分 | 等级 | 成就主题 |
|---|---|---|---|---|
| 13 音乐 | 伪签到(只 Toast) | — | Lv.4 | 通用徽章 |
| 14 运动 | +10 积分(真交互) | 运动积分 | Lv.5 | 运动徽章 |
| 15 环保 | +5 环保积分(真交互) | 环保积分 | Lv.6 | 环保徽章 |
系列的游戏化从"伪"到"真"、从"通用"到"主题化"——App 15 的"环保积分/环保成就"让游戏化与产品主题深度绑定。

十、与 App 14 我的页的同构总结
| 维度 | App 14 运动我的 | App 15 环保我的 |
|---|---|---|
| 布局 | 6 块同构 | 6 块同构 |
| 签到 | +10 积分 | +5 积分 |
| 成就 | 运动 6 徽章 | 环保 6 徽章 |
| 菜单 | 6 项 | 6 项(数字3/NEW) |
| 周图 | 运动时长 7.5h | 分类次数 47 次 |
| About | 运动预约 v1.0.0 | 垃圾分类 v1.0.0 |
两页 95% 代码相同,差异只在数据——这是"模板复用"的最强证明:一个"绿色个人中心"模板,换数据源即可生成任意主题的个人页。

十一、数据一致性与口径
本页数据与首页/记录页的呼应:
- 分类 328 = 首页"本月分类 328" = 分类页"总记录 328"(三页一致 ✓)
- 准确率 92% = 首页"准确率 92%"(两页一致 ✓)
- 减碳 15.6kg = 首页"本月减碳 15.6kg"(两页一致 ✓)
- 本周 47 次 vs 首页"平均 68%"(口径不一致 ✗,详见第五节)
"三个页面共享 328/92%/15.6kg,但周数据口径不统一"——demo 的"大部分一致 + 小部分瑕疵"是真实项目数据的常态。读者应学习"跨页一致"的好习惯,也警惕"口径不统一"的坑。
十二、环保积分体系的设计
App 15 的积分体系(签到 +5 环保积分)背后应该有完整的积分经济模型:
1. 积分获取渠道(多源):签到 +5、每次分类 +2、分享环保知识 +1、邀请好友 +50、完成测试 +10——"行为越多、积分越多",激励用户持续使用。
2. 积分消耗渠道(闭环):积分兑换(菜单第 4 项"积分兑换")——环保袋、种子、绿植、优惠券——"积分能花出去才有价值"。没有消耗渠道的积分体系会"通货膨胀",用户失去获取动力。
3. 积分与经验分离:本页经验值(1860/3000 升级 Lv.6)和环保积分(签到 +5)是两套体系——经验决定等级(身份),积分决定兑换(资产)。"等级体系(成长)+ 积分体系(经济)"双轨是游戏化设计的标准架构,微信运动(步数=经验)、支付宝(蚂蚁森林能量=积分)都如此。
4. 防刷机制:签到"每天一次"(checked + 日期持久化)、分类"同物品重复不计数"(去重)、分享"每日上限 3 次"——"防刷"是积分经济模型的安全底线。
demo 只实现了"签到 +5"一个积分动作,但"积分 = 多源获取 + 兑换消耗 + 防刷"的完整模型值得在真实项目中设计——"积分体系是留存的核心引擎"。

十三、个人中心的"身份叙事"进化
对比系列 3 个"我的页",可以清晰看到**"身份叙事"的进化**:
| App | 用户 | 等级 | Slogan | 叙事主线 |
|---|---|---|---|---|
| 13 音乐 | 小明同学 | Lv.4 | 活跃用户·已使用 28 天 | 使用时长(我用了多久) |
| 14 运动 | 张运动 | Lv.5 | 运动达人·已坚持 28 天 | 坚持天数(我坚持多久) |
| 15 环保 | 李环保 | Lv.6 | 环保达人·减碳 15.6kg | 环保成果(我贡献了什么) |
叙事从"使用时长 → 坚持天数 → 环保成果"——App 15 的"减碳 15.6kg"是最强的身份标签:"我做了什么贡献"比"我用了多久"更有激励性(贡献感 = 社会价值感)。
"成果型身份"(减碳 kg/种树棵数/帮助人数)是公益类/环保类 App 的黄金标准——支付宝蚂蚁森林把"种树"做成身份("我已经种了 3 棵树"),激励效果远大于"连续签到 30 天"。
设计启示:个人中心的 Slogan 应该写"用户的贡献成果"而非"用户的使用时长"——前者是"我给世界带来了什么",后者是"我在 App 上花了多少时间"。
十四、4 个 Tab 的完整闭环
App 15 四个 Tab 构成完整闭环:
首页(♻️ 知识入口)
↓ 看到"分类指南 45%"→ 想学
识别(📷 查询分类)
↓ 查到"旧报纸 → 可回收物"→ 产生记录
分类(🗂️ 记录管理)
↓ 看到"占比厨余 48%"→ 调整习惯
我的(👤 身份沉淀)
↓ 签到 +5 → 经验涨 → 成就解锁 → 身份升级
↓ 回到首页看到"减碳 15.6kg"→ 继续使用
"知识 → 行动 → 记录 → 身份"四环相扣,每个 Tab 都有明确的"下一步引导"(首页引导学、识别引导查、分类引导改、我的引导签)——"Tab 间闭环"是系列 demo 的最高级设计(前几代 App 的 Tab 相对独立)。
十五、小结
App 15「智能垃圾分类」我的页解析完毕。Lv.6 环保达人 + 四色编码 + doSearch 真逻辑 + 环保游戏化 + 积分经济模型,让 App 15 成为系列的"环保主题标杆"。
更多推荐




所有评论(0)