鸿蒙原生应用 ArkUI 实战:2 列彩色网格 + 分类色金额 —— 票据分类页的统计架构
鸿蒙原生应用 ArkUI 实战:2 列彩色网格 + 分类色金额 —— 票据分类页的统计架构
App 52「电子票据管理」分类页(Func2Tab),主题色
#0066CC科技蓝,4 个 Tab 分别为首页(🧾)、上传(📤)、分类(📂)、我的(👤)。本篇基于52-e-receipt/entry/src/main/ets/pages/Func2Tab.ets(共 70 行)逐段拆解,附 4 张实机截图。

一、整体结构:两区"Header + 分类网格"布局
分类页是极简的"品牌头部 + 统计网格"两区布局——2 个 @Builder 块:
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 12 }) {
this.CatGrid()
}
.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)
}
2 块结构:Header(单行品牌头)→ CatGrid(6 分类 2 列网格)。分类页是"统计页"——用网格把 48 张票据按 6 个消费分类展示(每类多少张、花了多少钱),让用户一眼看清"钱都花在哪类上"。
二、CatItem 数据模型:6 分类 + 分类色
interface CatItem {
id: number;
emoji: string;
name: string;
count: number;
amount: number;
color: string;
}
private cats: CatItem[] = [
{ id: 1, emoji: '🍽️', name: '餐饮', count: 12, amount: 1288, color: '#FF6B6B' },
{ id: 2, emoji: '🚕', name: '交通', count: 8, amount: 456, color: '#4A90D9' },
{ id: 3, emoji: '🏨', name: '住宿', count: 3, amount: 1560, color: '#9B51E0' },
{ id: 4, emoji: '🛒', name: '购物', count: 15, amount: 2340, color: '#27AE60' },
{ id: 5, emoji: '💼', name: '办公', count: 6, amount: 680, color: '#F2994A' },
{ id: 6, emoji: '📦', name: '其他', count: 4, amount: 320, color: '#95A5A6' }
];
CatItem 六字段含 color——每类一个专属颜色(红/蓝/紫/绿/橙/灰),分类色体系是本页最大特色。6 分类覆盖餐饮/交通/住宿/购物/办公/其他,与上传页 cats 数组完全一致。
三、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 号、safeTop + 56 固定高、文字贴底)——功能页 Header 复用范式。
四、CatGrid:六分类 2 列彩色网格
CatGrid() {
Grid() {
ForEach(this.cats, (c: CatItem) => {
GridItem() {
Column({ space: 10 }) {
Row() { Text(c.emoji).fontSize(28) }
.width(52).height(52).backgroundColor(c.color + '22').borderRadius(26).justifyContent(FlexAlign.Center)
Text(c.name).fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text)
Text(c.count + ' 张票据').fontSize(11).fontColor(C.textDim)
Text('¥' + c.amount).fontSize(16).fontWeight(FontWeight.Bold).fontColor(c.color)
}
.width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
.onClick(() => { promptAction.showToast({ message: c.name + ' ' + c.count + ' 张' }); })
}
}, (c: CatItem) => c.id.toString())
}.columnsTemplate('1fr 1fr').columnsGap(12).rowsGap(12).width('100%')
}
逐点拆解:
- 52×52 分类色透明底圆标:
backgroundColor(c.color + '22')——HEX + "22" = 约 13% 透明度的分类色底(#FF6B6B22= 红 13% 透明),emoji 28 号居中,圆形(26 半径)。每类一个专属颜色,视觉一眼区分消费类别。 - 分类名 + 张数:15 号 Bold 分类名 + 11 号淡灰"12 张票据"——名称主标识、张数弱化处理。
- 分类色金额:
fontColor(c.color)——16 号 Bold¥1288用分类本身的颜色——金额颜色 = 分类颜色,金额与分类强绑定,比全用主题蓝更有信息量。 - 2 列网格:
columnsTemplate('1fr 1fr')+ 12 间距——6 分类排为 3 行 2 列。 - 整卡点击:
onClick弹 Toast"餐饮 12 张"——产品化后进该分类的票据列表。

五、HEX 透明度拼接技巧
.width(52).height(52).backgroundColor(c.color + '22').borderRadius(26).justifyContent(FlexAlign.Center)
Text('¥' + c.amount).fontSize(16).fontWeight(FontWeight.Bold).fontColor(c.color)
同一 color 字段派生两种用法:
c.color + '22':8 位色值(#FF6B6B22)= 13% 透明度浅底——图标背景。c.color:6 位色值(#FF6B6B)= 实色——金额文字颜色。
一个颜色字段同时驱动图标底色和金额颜色,保证"同色系"一致性——这是色值字符串复用的技巧,也是本页"类别色体系"的核心实现。

六、统计校验:六分类数字的自洽性
{ id: 1, emoji: '🍽️', name: '餐饮', count: 12, amount: 1288, color: '#FF6B6B' },
{ id: 2, emoji: '🚕', name: '交通', count: 8, amount: 456, color: '#4A90D9' },
{ id: 3, emoji: '🏨', name: '住宿', count: 3, amount: 1560, color: '#9B51E0' },
{ id: 4, emoji: '🛒', name: '购物', count: 15, amount: 2340, color: '#27AE60' },
{ id: 5, emoji: '💼', name: '办公', count: 6, amount: 680, color: '#F2994A' },
{ id: 6, emoji: '📦', name: '其他', count: 4, amount: 320, color: '#95A5A6' }
两组交叉验证:
- 张数合计:12 + 8 + 3 + 15 + 6 + 4 = 48 张 = 我的页"票据总数 48"。
- 金额合计:1288 + 456 + 1560 + 2340 + 680 + 320 = 6644 元 ≈ 我的页"¥6.6k"。
- 单类均额:餐饮 1288÷12 ≈ 107 元/张(高频低额)、住宿 1560÷3 = 520 元/张(低频高额)——数据分布符合真实消费逻辑。

七、系列横向对比:分类/统计网格的四种形态
| 统计页 | 代表 App | 统计方式 | 色彩体系 | 核心特色 |
|---|---|---|---|---|
| 彩色网格 | App 52 分类 | 2 列网格 + 分类色金额 | 6 分类 6 色 | 金额着色 |
| 柱状图 | App 47 统计 | 手写柱状图 + 进度条 | 主题单色 | 图表驱动 |
| 话题网格 | App 42 树洞 | 2 列网格 + 话题卡 | 主题单色 | 纯类别浏览 |
| 投票结果 | App 49 结果 | 冠军卡 + 投票条 | 主题单色 | 单选高亮 |
差异点:App 52 的"一卡一色 + 金额着色"——每个分类有自己的颜色(红/蓝/紫/绿/橙/灰),金额也用分类色(而非主题蓝),是系列中少见的"类别色体系"——信息编码比单色方案更丰富。
八、开发者视角:调试与验证技巧
- HEX 透明度拼接:
c.color + '22'是字符串拼接——注意透明度值必须两位十六进制(22 ≈ 13%),如果分类色来自接口数据需确认格式(无#前缀会失效)。 - 分类色可读性:金额用分类色(如灰
#95A5A6)在白色卡片上对比度偏低——浅色分类色建议金额加深 30%(#95A5A6→#7F8C8D)。 - 网格卡片高度:
Grid行高由内容撑开——6 卡 3 行 2 列在小屏可能溢出,当前Scroll包裹已兜底。 - 整卡点击:
onClick弹 Toast"餐饮 12 张"——产品化后跳该分类的票据列表(餐饮下 12 张明细)。 - key:
c.id.toString()稳定唯一(1-6)。
九、演进方向
| 方向 | 当前状态 | 产品化演进 |
|---|---|---|
| 动态聚合 | 硬编码 6 类数据 | 按消费类型分组聚合(filter + reduce) |
| 分类跳转 | Toast"餐饮 12 张" | 进该分类票据列表(12 张明细) |
| 二级分类 | 6 类扁平 | 餐饮下细分堂食/外卖/饮品 |
| 占比图表 | 纯网格 | 环形图/柱状图展示各类占比 |
| 空分类 | 无 | 无票据的分类显示空状态引导 |
十、一句话总结
分类页以"2 列彩色网格"完成了票据的归类总览。c.color + '22' HEX 透明度拼接派生图标浅底、fontColor(c.color) 分类色金额着色(一卡一色 + 金额同色)、columnsTemplate('1fr 1fr') 2 列网格 3 行排布——70 行代码,一个"钱都花在哪类一目了然"的统计页,也是分类色体系的典型实现。

更多推荐





所有评论(0)