【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. 空状态提升体验,有记录时自然过渡到列表

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

相关推荐
万添裁11 分钟前
huawei 机考
算法·华为·深度优先
nashane8 小时前
HarmonyOS Wi-Fi连接用户操作监听全解析:从系统弹框到Promise回调
华为·harmonyos·harmonyos 5
Lanren的编程日记11 小时前
Flutter 鸿蒙应用数据版本管理实战:版本记录+版本回退+版本对比,实现全链路数据版本控制
flutter·华为·harmonyos
我是大聪明.12 小时前
DeepSeek V4 Pro + 华为昇腾910:国产大模型落地的性能实测与深度解析
人工智能·华为
木斯佳13 小时前
HarmonyOS 本地存储实战:记账本案例改造实现日历联动
华为·harmonyos
李游Leo14 小时前
别让一张 12MB 的照片拖垮页面:ImageSource / PixelMap / ImagePacker 的工程化处理链路
harmonyos
nashane14 小时前
HarmonyOS 6学习:画中画(PiP)状态同步与场景化实战指南
学习·pip·harmonyos·harmonyos 5
@不误正业14 小时前
鸿蒙小艺智能体开放平台实战-接入系统级AI-Agent能力
人工智能·华为·harmonyos
IntMainJhy17 小时前
「Flutter三方库sqflite的鸿蒙化适配与实战指南:从入门到踩坑的本地数据库开发全记录」
数据库·flutter·华为·信息可视化·数据库开发·harmonyos
前端技术20 小时前
HarmonyOS开发:鸿蒙应用开发发展史
华为·harmonyos