鸿蒙 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 块结构:

  1. SummaryCard — 深灰渐变月度卡(8 月总费用 ¥286)
  2. BarChart — 月度费用趋势柱状图(4-8 月)
  3. SectionTitle — "地点消费"标题
  4. PlaceList — 3 条地点统计列表(次数 + 金额)

费用页是"统计页"——先看当月总额(¥286),再看月度趋势(4-8 月 220-310 元波动、6 月最高),最后按地点看消费分布(公司车库 400 元占大头)。总览 → 趋势 → 结构三层递进,与 App 54 订阅统计、App 47 班费统计同属"数据可视化页"。

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

二、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]] })
}

技术拆解:

  1. 深灰渐变:linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })——从 #2D3436 渐变到 #636E72,与首页汇总卡同款渐变(品牌统一),深灰传达停车场景的沉稳感。
  2. 主金额 36 号:¥286 用 36 号 Bold 白字——比首页的 32 号更大(统计页是全屏分析,当月总额是唯一焦点),8 月停车总费用是本页核心数字。
  3. 左对齐布局:alignItems(HorizontalAlign.Start) 文本左对齐——与首页居中卡片不同(首页"标签上金额下"、本页"金额上标签下"且左对齐),变化体现"汇总卡"的灵活变体。
  4. 数据自洽:¥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 元

技术拆解:

  1. 纯 ArkUI 柱状图:Column().width(28).height(val * 110 / maxVal())——柱高 = 数值 × 比例系数 ÷ 最大值(每根柱按比例缩放,6 月 310 元最高占满 110,其余按比例),不依赖第三方图表库(App 47/54 同款手绘手法)。
  2. 深灰柱体:28 宽深灰柱(C.primary)+ borderRadius({ topLeft: 4, topRight: 4 })——只圆顶部两角(柱底贴基线),深灰柱与主题统一。
  3. 柱顶金额 + 底部月份:9 号淡灰金额(¥220)+ 10 号月份(4月)——每根柱上下两个标签(数据值 + 横轴刻度)。
  4. 基准对齐:height(160).alignItems(VerticalAlign.Bottom) + 每列 justifyContent(FlexAlign.End)——所有柱底部对齐(纵向从底部生长)。
  5. 动态比例:maxVal() 动态求最大值(310)——柱高相对最大值缩放,数据变化自动适配。
  6. 趋势解读: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 元

卡片细节:

  1. 44×44 圆形浅灰底图标:backgroundColor(C.primarySoft)(#E9ECEE)+ borderRadius(22)(正圆,不同于首页的圆角方块)——圆形图标块(费用页的视觉变体),22 号 emoji(🏢🅿️🏥)。
  2. 地点名 + 次数:14 号地点名 + 12 号淡灰"20 次停车"——地点与频次(停了多回),layoutWeight(1) 撑开。
  3. 深灰金额:15 号 Bold ¥400 用 C.primary(深灰)——金额用主题深灰(区别于 App 52 的彩色金额、App 54 的品牌色金额),深灰金额在费用页保持"沉稳中性"(统计页不需要彩色强调,深灰统一)。
  4. 数据自洽:公司车库 20 次 × 20 元 = 400 元(首页公司单次 20 元)、万达 8 次 × 12 元 = 96 元(首页万达单次 12 元)——单价 × 次数 = 累计与首页完全对账;市医院 3 次 × 8 元 = 24 元(首页医院单次 8 元)。
  5. 无免费地点:超市免费停车(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 的实现提炼四个易踩坑点:

  1. 柱高比例系数:height(val * 110 / maxVal())——固定系数 110 是"最高柱像素高"(容器 160 高,柱区 110 + 标签预留 50),调整图表大小时需同步调整系数,用"容器高 - 标签预留"推导。
  2. 免费地点的统计排除:费用页地点列表只有收费地点——统计时需过滤 fee = 0 的记录(免费停车不进入金额统计),但"次数"是否包含免费需产品决策(当前"次数"是收费次数)。
  3. 地点聚合逻辑:places 写死(公司/万达/医院)——产品化应由停车记录按地点分组聚合(groupBy 地点,count 次数、sum 金额),新增地点自动进入列表,避免"记录有万达但统计没万达"。
  4. 金额单位与对齐:¥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 次,读者可对照源码与首页数据逐一验证,这是数据自洽在统计页的典型体现。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐