【HarmonyOS 6】今日统计卡片实战:运动记录数据概览

一、案例背景

在移动端"运动记录"页面里,用户最先关心的是今天运动了多久、消耗了多少热量。与其把这些数据隐藏在列表里,不如用一张"今日统计卡"直接放在顶部,形成清晰的视觉焦点。

本案例面向 HarmonyOS 6 初学者,聚焦一个细化功能:今日统计卡 + 空状态提示。实现目标如下:

  • 顶部两列指标卡,展示"运动时长"和"消耗热量"
  • 下方列表为空时显示友好的空状态
  • 有记录时显示运动列表

二、完整代码实现

2.1 今日统计卡

typescript 复制代码
        // 今日统计
        Row() {
          Column() {
            Text(this.getTotalDuration().toString())
              .fontSize(this.getStatNumberSize())
              .fontWeight(FontWeight.Bold)
              .fontColor($r('app.color.exercise_orange'))
            Text('运动时长(分钟)')
              .fontSize(this.getStatLabelSize())
              .fontColor($r('app.color.text_secondary'))
          }
          .layoutWeight(1)

          Column() {
            Text(this.getTotalCalories().toString())
              .fontSize(this.getStatNumberSize())
              .fontWeight(FontWeight.Bold)
              .fontColor($r('app.color.exercise_orange'))
            Text('消耗热量(kcal)')
              .fontSize(this.getStatLabelSize())
              .fontColor($r('app.color.text_secondary'))
          }
          .layoutWeight(1)
        }
        .width('100%')
        .padding(this.getCardPadding() as Padding)
        .backgroundColor($r('app.color.card_background'))
        .borderRadius(this.getCardRadius())
        .margin({ left: this.getPagePaddingValue(), right: this.getPagePaddingValue() } as Padding)

关键点:

  • Row + 两个 Column 实现左右两列指标
  • layoutWeight(1) 让两列均分宽度
  • 卡片样式通过背景色和圆角形成"统计卡"的视觉块

2.2 今日记录列表与空状态

typescript 复制代码
        // 今日记录列表
        Text('今日运动')
          .fontSize(this.getSectionTitleSize())
          .fontWeight(FontWeight.Medium)
          .fontColor($r('app.color.text_primary'))
          .width('100%')
          .padding({ left: this.getPagePaddingValue(), top: this.getSectionGap(), bottom: this.getItemGap() } as Padding)

        if (this.exerciseRecords.length === 0) {
          Column() {
            Text('🏃')
              .fontSize(this.getEmptyIconSize())
              .fontColor($r('app.color.text_secondary'))
            Text('今天还没有运动记录')
              .fontSize(this.getBodyTextSize())
              .fontColor($r('app.color.text_primary'))
              .margin({ top: this.getItemGap() } as Padding)
          }
          .width('100%')
          .layoutWeight(1)
          .justifyContent(FlexAlign.Center)
        } else {
          List() {
            ForEach(this.exerciseRecords, (record: ExerciseRecordData) => {
              ListItem() {
                Row() {
                  Text(record.icon)
                    .fontSize(this.getItemIconSize())

                  Column() {
                    Text(record.typeName)
                      .fontSize(this.getBodyTextSize())
                      .fontColor($r('app.color.text_primary'))
                    Text(`${record.duration}分钟 · ${record.calories}kcal`)
                      .fontSize(this.getSmallTextSize())
                      .fontColor($r('app.color.text_secondary'))
                      .margin({ top: 2 } as Padding)
                  }
                  .alignItems(HorizontalAlign.Start)
                  .margin({ left: 12 } as Padding)

                  Blank()

                  Text(record.time)
                    .fontSize(this.getSmallTextSize())
                    .fontColor($r('app.color.text_secondary'))
                }
                .width('100%')
                .padding(this.getItemPadding() as Padding)
                .backgroundColor($r('app.color.card_background'))
                .borderRadius(getValueByBreakpoint(this.currentBreakpoint, new BreakpointValue<number>(8, 10, 12)))
              }
              .margin({ left: this.getPagePaddingValue(), right: this.getPagePaddingValue(), bottom: this.getItemGap() } as Padding)
              .swipeAction({
                end: this.ExerciseDeleteButton(record.id)
              })
            })
          }
          .padding({ bottom: getFloatingNavSafePadding(this.currentBreakpoint) } as Padding)
          .layoutWeight(1)
        }

这里包含两个关键体验:

  • 无记录时:显示图标 + 引导文字,避免页面空白
  • 有记录时:展示列表项,补充时长、热量与时间

空状态截图:

三、总结

本文实现了一个完整的移动端"今日统计卡 + 空状态"方案,核心要点包括:

  1. Row + layoutWeight 实现左右两列指标
  2. 卡片式背景与圆角增强视觉聚焦
  3. 空状态提升体验,有记录时自然过渡到列表

掌握这个案例后,你可以迁移到饮水、睡眠、打卡等模块,快速搭建可视化的日统计卡片。

相关推荐
行者-全栈开发5 小时前
【鸿蒙心迹】深色模式适配全链路——从配置到自定义(HarmonyOS 7.x)
华为·harmonyos
行者-全栈开发15 小时前
【鸿蒙心迹】国际化 i18n 与多语言资源管理实战(HarmonyOS 7.x)
ui·华为·重构·国际化·harmonyos·多语言
OH_TPC17 小时前
HarmonyOS APP开发---"云客服"远程视频客服App,需要用到这个库
harmonyos
逆回1 天前
给鸿蒙手机做一只 3D 宠物:五个把我卡住的问题
harmonyos
钉先生贾1 天前
性能、体积与稳定性:怎样写出可信的适配结论
华为·harmonyos
笑 总不会犯错2 天前
摆脱多端数据撕裂,鸿蒙分布式数据库同步与冲突合并
harmonyos
用户117910488332 天前
鸿蒙签名失败不是玄学:5 个证据点把 hapsigntool 一次排通 GitHub:swsgbl/hmharness
开源·ai编程·harmonyos
redtank20002 天前
纯血鸿蒙小工具三件套实测:弹幕手持、爱记录与仓库管理软件
学习·华为·智能手机·harmonyos
xyzzklk2 天前
变相解决华为Mate 8锁屏后无法建立入站网络连接
linux·运维·服务器·网络·华为·go·安卓
用户86194177207412 天前
uni-app 的蓝牙 API 在鸿蒙上不生效?我写了个兼容层,让老代码零改动跑起来
harmonyos