在移动端应用中,用户打开运动记录页面时,最关心的莫过于今天的运动时长和消耗热量。与其让这些关键数据淹没在冗长的列表中,不如通过一张“今日统计卡片”将其置于页面顶部,形成清晰的视觉焦点。本文面向HarmonyOS 6初学者,深入拆解如何实现一个包含“今日统计卡”和“空状态提示”的细化功能模块,帮助你快速掌握卡片式布局与状态管理的核心技巧。
一、案例背景与设计思路
在移动端“运动记录”页面的设计中,用户体验的核心在于信息获取的即时性。用户不需要翻找列表,就能一眼看到今天的运动总时长和总热量消耗。这种设计思路其实借鉴了多种编程语言中的模块化思想——例如在Java或Python中,我们常将核心功能封装为独立模块,而在HarmonyOS 6中,则通过组件化布局来实现。
本案例面向HarmonyOS 6初学者,聚焦一个细化功能:今日统计卡 + 空状态提示。实现目标如下:
- 顶部两列指标卡,展示“运动时长”和“消耗热量”
- 下方列表为空时显示友好的空状态
- 有记录时显示运动列表
这种设计不仅适用于运动记录,还可以轻松迁移到饮水、睡眠、打卡等模块,快速搭建可视化的日统计卡片。如果你熟悉TypeScript或C++中的状态管理,你会发现HarmonyOS 6的响应式设计与之异曲同工——数据驱动UI更新,让开发更高效。

上图展示了页面的整体布局效果:顶部是统计卡片,下方是列表区域。当列表为空时,会显示空状态提示;有数据时则展示具体记录。这种设计避免了页面空白带来的困惑,提升了用户体验。
二、完整代码实现与深度解析
2.1 今日统计卡:两列指标卡布局
统计卡片是页面的核心视觉焦点。我们使用Row + 两个Column实现左右两列指标,并通过layoutWeight(1)让两列均分宽度。卡片样式通过背景色和圆角形成“统计卡”的视觉块,让数据一目了然。
// 今日统计
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容器:水平排列左右两列,通过
layoutWeight(1)实现等宽布局,无需手动计算宽度。 - Column子组件:每列内部垂直排列图标、数值和单位,形成清晰的层级结构。
- 卡片样式:使用背景色(如白色或浅灰色)和圆角(如12px)模拟物理卡片的视觉效果,增强层次感。
这种布局方式与Go语言中的结构体设计有异曲同工之妙——每个子组件就像结构体中的字段,职责单一且可复用。如果你有过Java或TypeScript的开发经验,你会发现这种声明式UI更接近于前端框架的组件化思想。

上图展示了统计卡片的实际渲染效果:左侧显示“运动时长”,右侧显示“消耗热量”,每个指标都配有图标和具体数值,视觉上非常清晰。
2.2 今日记录列表与空状态设计
列表区域是页面数据的主要展示区。我们通过条件渲染来处理两种状态:有记录时展示列表项,无记录时显示空状态提示。这种设计在Python或C++的UI框架中也很常见,但HarmonyOS 6通过内置的if/else语法让逻辑更直观。
// 今日记录列表
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)
}
这段代码包含两个关键体验:
- 无记录时:显示图标 + 引导文字(如“今天还没有运动记录哦”),避免页面空白,同时给予用户温和的提示。
- 有记录时:展示列表项,每项包含运动时长、消耗热量和具体时间,信息完整且易于浏览。
⚠️ 常见问题:空状态图标不显示? 检查图片资源路径是否正确,或使用系统内置图标。另外,确保@State装饰的数据变量正确绑定,否则列表不会响应数据变化。

上图展示了空状态下的页面效果:一个跑步图标配合“暂无运动记录”的文字提示,视觉上友好且不突兀。当用户开始运动后,列表会自动填充,实现自然过渡。
[AFFILIATE_SLOT_1]三、总结与最佳实践
本文实现了一个完整的移动端“今日统计卡 + 空状态”方案,核心要点包括:
- Row + layoutWeight:实现左右两列指标,宽度自动均分,无需手动计算。
- 卡片式背景与圆角:增强视觉聚焦,让数据更突出。
- 空状态提升体验:有记录时自然过渡到列表,无记录时避免空白页面。
掌握这个案例后,你可以轻松迁移到其他日统计模块(如饮水、睡眠、打卡),快速搭建可视化的统计卡片。如果你熟悉TypeScript或Go,甚至可以进一步封装为可复用的组件库,提升开发效率。
最后,建议在开发中注意以下几点:
- 数据绑定:确保
@State或@Prop装饰的变量正确绑定,避免UI不更新。 - 性能优化:如果列表数据较多,考虑使用
LazyForEach实现懒加载。 - 可访问性:为图标和文字添加
accessibilityText,提升无障碍体验。
希望本文能帮助你快速上手HarmonyOS 6的卡片式布局与状态管理,打造出更优秀的移动端应用!
浙公网安备 33010602011771号