鸿蒙 ArkUI 实战:不引图表库 —— 停车费用页手写的五柱趋势图与地点消费榜
鸿蒙 ArkUI 实战:不引图表库 —— 停车费用页手写的五柱趋势图与地点消费榜
App 56「停车缴费记录」费用页(Func2Tab),主题色
#2D3436深灰黑。本页是停车费用的"统计页"——白色单行 Header("费用统计"20 号加粗) + 深灰渐变月度卡(¥286 36 号加粗白字 + "8月停车总费用") + 月度费用趋势柱状图(4月 220 / 5月 260 / 6月 310 / 7月 245 / 8月 286 元,深灰柱 + 柱顶金额 + 月份标签) + SectionTitle(地点消费)+ 3 条地点统计列表(🏢 公司车库 20 次 ¥400 / 🅿️ 万达广场 8 次 ¥96 / 🏥 市医院 3 次 ¥24,每条含 44×44 圆形浅灰底图标 + 地点名 + 次数 + 深灰金额)。本篇基于56-parking-record/entry/src/main/ets/pages/Func2Tab.ets(共 111 行)逐段拆解,附 4 张实机截图。
一、整体结构:四区"Header + 月度卡 + 柱状图 + 地点列表"布局
费用页是"月度总览 + 趋势 + 地点结构"的分析布局——4 个 @Builder 块:
build() {
Column() {
this.Header()
Scroll() {
Column({ space: 14 }) {
this.SummaryCard()
this.BarChart()
this.SectionTitle('地点消费')
this.PlaceList()
}
.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)
}
4 块结构:
- SummaryCard — 深灰渐变月度卡(8 月总费用 ¥286)
- BarChart — 月度费用趋势柱状图(4-8 月)
- SectionTitle — "地点消费"标题
- PlaceList — 3 条地点统计列表(次数 + 金额)
费用页是"统计页"——先看当月总额(¥286),再看月度趋势(4-8 月 220-310 元波动、6 月最高),最后按地点看消费分布(公司车库 400 元占大头)。总览 → 趋势 → 结构三层递进,与 App 54 订阅统计、App 47 班费统计同属"数据可视化页"。
二、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 号、固定高、文字贴底),与记录页、我的页同款。"费用统计"点明本页职能——对停车费用做统计。

三、SummaryCard:深灰渐变月度卡
SummaryCard() {
Column({ space: 6 }) {
Text('¥286').fontSize(36).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('8月停车总费用').fontSize(13).fontColor('#FFFFFF').opacity(0.9)
}
.width('100%').padding(24).borderRadius(D.rLg).alignItems(HorizontalAlign.Start)
.linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}
技术拆解:
- 深灰渐变:
linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })——从#2D3436渐变到#636E72,与首页汇总卡同款渐变(品牌统一),深灰传达停车场景的沉稳感。 - 主金额 36 号:
¥286用 36 号 Bold 白字——比首页的 32 号更大(统计页是全屏分析,当月总额是唯一焦点),8 月停车总费用是本页核心数字。 - 左对齐布局:
alignItems(HorizontalAlign.Start)文本左对齐——与首页居中卡片不同(首页"标签上金额下"、本页"金额上标签下"且左对齐),变化体现"汇总卡"的灵活变体。 - 数据自洽:¥286 = 首页"本月停车费 286.00" = 柱状图"8月 ¥286"——三个数据源完全一致(当月总额贯穿首页与费用页)。
四、BarChart:月度费用趋势柱状图
BarChart() {
Column({ space: 14 }) {
Text('月度费用趋势').fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
Row() {
ForEach(this.months, (m: string, idx: number) => {
Column({ space: 6 }) {
Text('¥' + this.monthVals[idx]).fontSize(9).fontColor(C.textDim)
Column()
.width(28).height(this.monthVals[idx] * 110 / this.maxVal())
.backgroundColor(C.primary).borderRadius({ topLeft: 4, topRight: 4 })
Text(m).fontSize(10).fontColor(C.textSub)
}.layoutWeight(1).justifyContent(FlexAlign.End)
}, (m: string) => m)
}.width('100%').height(160).alignItems(VerticalAlign.Bottom)
}
.width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}
5 个月数据(20-21 行):
| 月份 | 4月 | 5月 | 6月 | 7月 | 8月 |
|---|---|---|---|---|---|
| 费用 | 220 元 | 260 元 | 310 元 | 245 元 | 286 元 |
技术拆解:
- 纯 ArkUI 柱状图:
Column().width(28).height(val * 110 / maxVal())——柱高 = 数值 × 比例系数 ÷ 最大值(每根柱按比例缩放,6 月 310 元最高占满 110,其余按比例),不依赖第三方图表库(App 47/54 同款手绘手法)。 - 深灰柱体:28 宽深灰柱(
C.primary)+borderRadius({ topLeft: 4, topRight: 4 })——只圆顶部两角(柱底贴基线),深灰柱与主题统一。 - 柱顶金额 + 底部月份:9 号淡灰金额(¥220)+ 10 号月份(4月)——每根柱上下两个标签(数据值 + 横轴刻度)。
- 基准对齐:
height(160).alignItems(VerticalAlign.Bottom)+ 每列justifyContent(FlexAlign.End)——所有柱底部对齐(纵向从底部生长)。 - 动态比例:
maxVal()动态求最大值(310)——柱高相对最大值缩放,数据变化自动适配。 - 趋势解读:4 月最低 220、6 月最高 310、8 月 286——月度费用波动(220-310 元区间),8 月 286 与首页本月 286.00 完全一致,趋势图最后一个月即当前月。
五、PlaceList:地点消费列表
PlaceList() {
Column({ space: 10 }) {
ForEach(this.places, (p: PlaceStat) => {
Row({ space: 12 }) {
Row() { Text(p.emoji).fontSize(22) }
.width(44).height(44).backgroundColor(C.primarySoft).borderRadius(22).justifyContent(FlexAlign.Center)
Column({ space: 3 }) {
Text(p.name).fontSize(14).fontColor(C.text)
Text(p.count + ' 次停车').fontSize(12).fontColor(C.textDim)
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
Text('¥' + p.amount).fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.primary)
}
.width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke })
}, (p: PlaceStat) => p.id.toString())
}.width('100%')
}
3 个地点数据(23-27 行):
| 地点 | 次数 | 金额 |
|---|---|---|
| 🏢 公司车库 | 20 次 | 400 元 |
| 🅿️ 万达广场 | 8 次 | 96 元 |
| 🏥 市医院 | 3 次 | 24 元 |
卡片细节:
- 44×44 圆形浅灰底图标:
backgroundColor(C.primarySoft)(#E9ECEE)+borderRadius(22)(正圆,不同于首页的圆角方块)——圆形图标块(费用页的视觉变体),22 号 emoji(🏢🅿️🏥)。 - 地点名 + 次数:14 号地点名 + 12 号淡灰"20 次停车"——地点与频次(停了多回),
layoutWeight(1)撑开。 - 深灰金额:15 号 Bold
¥400用C.primary(深灰)——金额用主题深灰(区别于 App 52 的彩色金额、App 54 的品牌色金额),深灰金额在费用页保持"沉稳中性"(统计页不需要彩色强调,深灰统一)。 - 数据自洽:公司车库 20 次 × 20 元 = 400 元(首页公司单次 20 元)、万达 8 次 × 12 元 = 96 元(首页万达单次 12 元)——单价 × 次数 = 累计与首页完全对账;市医院 3 次 × 8 元 = 24 元(首页医院单次 8 元)。
- 无免费地点:超市免费停车(0 元)不在列表——费用页只统计收费地点,免费记录不进入费用统计(与首页"免费"记录呼应)。
六、跨页数据自洽:费用统计的全局闭环
费用页与首页、记录、我的三页形成闭环:
- 费用页"¥286 8月" ↔ 首页"本月停车费 286.00"——金额完全一致,首页从"月度总览"、费用页从"趋势 + 地点"双维度展示当月停车支出。
- 费用页"6月 310 最高" ↔ 柱状图趋势——月度波动(220-310)反映出行规律(6 月出行多停车费高、4 月最少),趋势图是停车支出的时间画像。
- 费用页"公司车库 20 次 400 元" ↔ 首页"公司地下车库 ¥20"——公司单次 20 元 × 20 次 = 400 元,单价 × 频次 = 地点累计,费用页的地点是首页记录的聚合。
- 费用页"万达 8 次 96 元" ↔ 首页"万达广场停车场 ¥12"——万达单次 12 元 × 8 次 = 96 元,均额对账(12 元/次)。
- 费用页 3 个地点 ↔ 记录页"常用地点"——公司/万达/医院都出现在常用地点胶囊(可快捷录入),录入地点 → 费用统计维度,免费地点(超市)仅记录不统计。
- 我的页"¥2.8k 累计费用" ↔ 费用页月度累计——费用页是"月"视角(4-8 月)、我的页是"累计"视角(全部历史约 2800 元),月度统计 → 总量累计。
七、系列横向对比:数据统计页的三种形态
系列中"数据统计"型页面各有侧重:
- App 56 费用统计(深灰
#2D3436):月度卡 + 柱状图 + 地点列表——"费用 + 地点"双维度(时间趋势 + 空间分布)。 - App 54 订阅统计(紫
#9B51E0):年度卡 + 柱状图 + 分类占比——"年度 + 分类"双维度。 - App 47 班费统计(绿
#00A862):余额卡 + 手写柱状图——"余额 + 收支"。 - App 50 室友评价(靛蓝
#5549A6):和谐度 + 星级 + 进度条——"评价维度"。
56 与 54 都是"汇总卡 + 柱状图 + 列表"的三区统计页,差异化在维度:54 按"分类"(视频/软件/云服务)、56 按"地点"(公司/万达/医院)——停车费用的天然维度是"地点"(在哪停车决定花多少),地点列表的"次数 + 金额"比分类占比更贴合停车场景(公司 20 次是高频、医院 3 次是低频)。深灰柱状图与深灰金额保持"沉稳中性"的统计气质。
八、开发者避坑:费用统计的四个细节
从 Func2Tab 的实现提炼四个易踩坑点:
- 柱高比例系数:
height(val * 110 / maxVal())——固定系数 110 是"最高柱像素高"(容器 160 高,柱区 110 + 标签预留 50),调整图表大小时需同步调整系数,用"容器高 - 标签预留"推导。 - 免费地点的统计排除:费用页地点列表只有收费地点——统计时需过滤 fee = 0 的记录(免费停车不进入金额统计),但"次数"是否包含免费需产品决策(当前"次数"是收费次数)。
- 地点聚合逻辑:
places写死(公司/万达/医院)——产品化应由停车记录按地点分组聚合(groupBy 地点,count 次数、sum 金额),新增地点自动进入列表,避免"记录有万达但统计没万达"。 - 金额单位与对齐:¥400/¥96/¥24 三位与两位混排——右对齐保证纵向可比(当前
Text('¥' + p.amount)直接拼接,对齐依赖文本宽度),产品化用统一对齐方式(右对齐已由 Row 布局保证)。
九、常见问题 FAQ
问:费用页的柱状图为什么 6 月最高(310 元)?答:演示数据设计 6 月为出行高峰(可能出差多、停车频繁),4 月最低(220 元,出行少)。产品化后每月费用由当月停车记录动态汇总——出行多的月份柱子高、少的月份矮,柱状图直接反映用户的出行节奏。
问:地点消费的公司车库 400 元是怎么算的?答:公司车库 20 次 × 每次 20 元 = 400 元——与首页"公司地下车库 ¥20"的单次费用对账(单价 20 元),20 次是累计在公司停车的次数。万达广场 8 次 × 12 元 = 96 元同理(首页万达单次 12 元),单笔与累计完全一致。
问:为什么费用页没有超市免费停车?答:因为费用页统计的是"停车费用"——超市免费停车费用为 0,进入统计没有意义(0 元不影响总额、不影响趋势),所以只统计收费地点。免费记录仍保留在首页"最近停车"列表(记录停车行为),但费用统计排除免费项。

十、验收与总结
本篇对 56-parking-record 费用页(Func2Tab,111 行)做了逐块拆解:
- 四区结构:Header(费用统计)+ SummaryCard(月度渐变卡)+ BarChart(五柱趋势图)+ SectionTitle + PlaceList(地点消费)
- 核心交互:无点击(纯数据展示),柱状图 ArkUI 手绘
- 主题色:
#2D3436深灰黑——月度卡渐变、柱状图柱体、地点金额 - 数据闭环:费用页 286/6月310/公司400 → 首页 286/公司20 → 记录页常用地点,四页同源
费用页是停车缴费记录的"支出分析"——月度卡给结论(8 月 286 元)、柱状图给趋势(4-8 月波动)、地点列表给结构(公司占大头 400 元),三图一页完成停车费用的全面分析。
十、扩展思考:从月度统计到停车消费洞察
费用页的演进方向是"停车消费洞察":第一是日均/次均成本分析——月度总费用(286 元)摊到天(286 ÷ 31 ≈ 9.2 元/天)或摊到次(286 ÷ 18 ≈ 15.9 元/次),让用户感知"每天停车平均花多少钱",比月度总额更有代入感;第二是地点成本对比——公司车库 400 元(20 次 × 20 元)与市医院 24 元(3 次 × 8 元)的对比,演进方向是"每地点次均成本"排序(医院次均 8 元最便宜、公司 20 元最贵),指导用户"能停便宜的就不停贵的";第三是月度预算预警——结合月度趋势(4-8 月 220-310 元),演进方向是设停车预算(如 300 元/月),超预算月份柱状图变红预警,柱状图是预算对比的天然载体;第四是出行方式对比——停车费用与公交/地铁成本的对比(打车 vs 开车的成本账),演进方向是引入替代出行成本参考,让用户理性选择出行方式。这四个方向都从费用页已有的柱状图与地点列表长出来,让"看统计"变成"做决策"。

十一、从设计稿到代码的映射
把费用页设计稿翻译成代码,有几组典型映射:第一,"月度渐变卡"映射为"渐变容器加 36 号金额"——设计稿的 8 月总费用卡,代码里用深灰渐变背景容器内放 36 号加粗金额与 13 号标签,左对齐排列;第二,"柱状图"映射为"等分行内的高度计算容器"——设计稿的五根深灰柱,代码里用五个等权重列,柱高按数值与最大值比例动态计算,柱顶金额与柱底月份标签;第三,"地点列表"映射为"圆形图标加信息加金额"——设计稿的地点消费行,代码里用圆形浅灰底图标、地点名与次数、深灰金额三段组合;第四,"三区布局"映射为"滚动容器内的三个卡片"——设计稿的月度卡、趋势图、地点列表,代码里用滚动容器包三个卡片按间距排列。这四组映射展示了"统计页"的完整翻译,手绘柱状图与圆形图标块是其中的视觉要点。
十二、常见问题 FAQ
问:柱状图 6 月 310 元最高有什么含义?答:演示数据设计 6 月为停车消费高峰(出行频繁),4 月 220 元最低(出行少)。月度波动(220-310)反映的是出行节奏——出差多的月份停车费高、居家多的月份低。产品化后每根柱由当月记录动态汇总,柱高变化直接对应实际出行情况。
问:地点消费为什么没有按占比展示(像 App 54 那样)?答:因为地点消费更适合"列表"而非"占比条"——3 个地点的次数与金额差异大(公司 20 次 vs 医院 3 次),列表的"次数 + 金额"比占比条信息更全(占比只有比例没有绝对值)。设计选择取决于数据形态:分类占比适合"结构清晰"的维度,地点次数适合"频次 + 金额"的维度。
问:为什么市医院只有 3 次 24 元?答:演示数据设计医院为低频停车场景(就医才去,3 次),公司为高频(每天上班,20 次),万达居中(购物,8 次)——三个地点覆盖"高频/中频/低频"的典型分布,让地点列表的"次数"维度有对比意义,也体现了"常用地点"(公司/万达/医院)与使用频率的对应。
十三、补充要点:费用页三个细节再思考
第一,关于柱状图与首页的数据呼应。柱状图最后一根(8月 ¥286)与首页"本月停车费 286.00"完全一致——趋势图以当前月收尾,用户看趋势时"最后一眼"落在当月,与首页数字对上,形成"首页给结论、费用页给过程"的呼应。第二,关于地点的圆形图标。费用页用正圆图标块(44×44、圆角 22)而首页用圆角方块(48×48、圆角 10)——同应用的图标容器两种形态(方块在列表、圆形在统计),圆形更"统计感"(像数据点),方块更"列表感",视觉上与页面职能匹配。第三,关于金额的中性呈现。费用页金额统一深灰(不彩色)——统计页追求"冷静的数据呈现",彩色金额会分散对趋势与结构的注意力,深灰让数据本身说话,这与首页的品牌色、费用页的深灰主题一脉相承。

十四、最后总结
费用页作为停车缴费记录的"统计页",用三个可视化区块完成了停车费用的完整分析:月度卡给结论(8 月 286 元)、柱状图给趋势(4-8 月 220-310 波动、6 月最高)、地点列表给结构(公司 400 元占大头、医院 24 元低频)。整页没有用户卡与菜单,是系列中"纯数据页"的又一代表——第 3 Tab 完全让给费用分析,体现停车记录"数据驱动"的产品重心。手绘柱状图与圆形图标块展示了 ArkUI 基础组件完成数据可视化的能力。从演示到产品,费用页的进化方向是动态聚合(数据驱动图表)、预算预警(超预算变红)、次均成本分析、出行方式对比,从"看统计"走向"做决策"。
十五、补充要点:柱状图与地点列表的细节再思考
本页的两个可视化区块有几个细节值得再思考:第一,柱状图的"当月收尾"——5 根柱以 8 月(286 元)收尾,与首页"本月停车费 286.00"完全一致——柱状图展示的是"过去到现在的趋势",最后一根永远落在当前月,用户看趋势时最后一眼看到的就是"本月数据",与首页对上号,这是"首页结论 + 费用页过程"的呼应设计;产品化后柱状图应随月份自动滚动(当前月永远在最后)。第二,地点列表的"次数 + 金额"双信息——每行同时展示"20 次停车"(频次)与"¥400"(金额),比单看金额多一层解读——公司 20 次 400 元说明"高频高额"(每天上班必停),医院 3 次 24 元说明"低频低额"(偶尔就医),频次与金额的组合让地点消费有"行为画像"。第三,圆形图标与方块图标的形态分工——本页圆形(44×44 正圆)与首页方块(48×48 圆角)区分页面职能(统计 vs 列表),但同一应用的图标 emoji 一致(🏢 公司、🅿️ 万达),用户跨页识别无门槛。第四,金额的右对齐纵向可比——三行金额右对齐成列(400/96/24),用户纵向扫一眼就能比较各地点花费大小,公司 400 元"一骑绝尘"一目了然,右对齐是数字列表的可比性基础。这四个细节共同保证费用页"看得懂、比得清、对得上账"。
十六、最后补充
费用页解析至此完整收尾:月度渐变卡、五柱趋势图、地点消费列表全部覆盖。读者可重点回顾柱状图高度公式(数值乘比例系数除最大值)与圆形图标块的实现——手绘图表与形态分工是统计页的视觉要点。停车费用的分析从这一页展开:286 元的当月结论、220 到 310 的月度波动、公司车库 400 元的占比,三组数据让用户既看到"花了多少"也看到"花在哪、怎么花的",这是停车缴费记录的数据分析能力。
补充说明:费用页的三个区块(月度卡、柱状图、地点列表)数据完全对账——月度卡 286 元等于柱状图 8 月 286 元,地点列表的公司 400 元等于单次 20 元乘 20 次,读者可对照源码与首页数据逐一验证,这是数据自洽在统计页的典型体现。

更多推荐




所有评论(0)