前言
本文将介绍如何使用HarmonyOS的ArkTS语言编写一个健康app中的统计数据卡片功能。该功能主要包括日期选择、热量统计和营养素统计三个部分。通过直观的界面展示,帮助用户了解自己的热量和营养素摄入情况,从而更好地管理自己的饮食和运动。
一、饮食记录UI设计分析图例
二、各组件的详细及联系
一、StatsCard
首先定义了一个名为 `StatsCard` 的组件,其主要功能是在健康应用中展示统计数据卡片。用户可以通过日期选择对话框选择特定日期,系统默认为当前日期的起始时间。所选日期将用于分析和展示该日的热量和营养素摄入情况。通过 `CalorieStats` 组件展示用户在选定日期内的饮食摄入数据,并显示运动消耗的热量信息。通过 `NutrientStats` 组件展示用户在选定日期内的碳水化合物、蛋白质和脂肪等营养素的摄入量。
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
import DateUtil from '../../common/utils/DateUtil'
import CalorieStats from './CalorieStats'
import DatePickDialog from './DatePickDialog'
import NutrientStats from './NutrientStats'
@Component
export default struct StatsCard {
@StorageProp('selectedDate') selectedDate:number = DateUtil.beginTimeOfDay(new Date())
controller:CustomDialogController = new CustomDialogController({
builder:DatePickDialog({selectedDate:new Date(this.selectedDate)})
})
build() {
Column(){
//1.日期信息
Row(){
Text(DateUtil.formatDate(this.selectedDate))
.fontColor($r('app.color.secondary_color'))
Image($r('app.media.ic_public_spinner'))
.width(20)
.fillColor($r('app.color.secondary_color'))
}
.padding(CommonConstants.SPACE_8)
.onClick(()=>this.controller.open())
//2.统计信息
Swiper(){
// 2.1.热量统计
CalorieStats()
// 2.2.营养素统计
NutrientStats()
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(CommonConstants.DEFAULT_18)
}
.width(CommonConstants.THOUSANDTH_940)
.backgroundColor($r('app.color.stats_title_bgc'))
.borderRadius(CommonConstants.DEFAULT_18)
}
}
上述代码运行截图:
二、DatePickDialog
`DatePickDialog` 组件是一个日期选择对话框,其主要功能是允许用户选择特定日期。该对话框使用 `DatePicker` 组件,其日期范围从 2020 年 1 月 1 日至当前日期。`DatePicker` 的 `start` 属性设置为 2020 年 1 月 1 日,`end` 属性设置为当前日期,`selected` 属性设置为 `this.selectedDate`,即默认选中当前日期。当用户在 `DatePicker` 中选择新日期时,会触发一个事件,通过该事件可以获取用户选择的年、月、日,并将这些值更新到 `this.selectedDate` 中。对话框底部提供取消按钮和确定按钮。点击取消按钮会关闭对话框,不保存任何更改;点击确定按钮会执行两个操作:首先,将选中的日期以毫秒形式保存到全局存储中,键名为 `selectedDate`;然后关闭对话框。
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants'
@Preview
@CustomDialog
export default struct DatePickDialog {
controller:CustomDialogController
selectedDate:Date = new Date()
build() {
Column({space:CommonConstants.SPACE_12}){
//1.日期选择器
DatePicker({
start: new Date('2020-01-01'),
end: new Date(),
selected: this.selectedDate
})
.onChange((value: DatePickerResult) => {
this.selectedDate.setFullYear(value.year, value.month, value.day)
})
//2.按钮
Row({space:CommonConstants.SPACE_12}){
Button('取消')
.width(120)
.backgroundColor($r('app.color.light_gray'))
.onClick(()=>this.controller.close())
Button('确定')
.width(120)
.backgroundColor($r('app.color.primary_color'))
.onClick(()=>{
//1.保存日期到全局存储
AppStorage.SetOrCreate('selectedDate',this.selectedDate.getTime())
//2.关闭窗口
this.controller.close()
})
}
}
.padding(CommonConstants.SPACE_12)
}
}
上述代码主要知识点:
- 这段 TypeScript 代码定义了一个名为 `DatePickDialog` 的结构体组件,用于显示一个日期选择对话框。以下是关键知识点的总结:
-
1. **导入语句**:
- - `import { CommonConstants } from '../../common/constants/CommonConstants'`:从常量文件中导入 `CommonConstants`,用于获取预定义的常量,例如间距值和颜色。
-
2. **装饰器**:
- - `@Preview` 和 `@CustomDialog`:这些装饰器标注了 `DatePickDialog` 是一个预览组件和自定义对话框组件。这些装饰器可能来自于某个 UI 框架或库,用于定义组件的行为和外观。
-
3. **成员变量**:
- - `controller: CustomDialogController`:用于控制对话框状态和行为的控制器。
- - `selectedDate: Date = new Date()`:存储用户选择的日期,默认为当前日期。
-
4. **build 方法**:
- - `build()` 方法定义了对话框的内容和布局:
- - 使用 `Column` 组件创建垂直布局,设置间距为 `CommonConstants.SPACE_12`。
- - 包含两个主要部分:
- - **日期选择器** (`DatePicker`):允许用户选择日期,并将选中的日期更新到 `this.selectedDate`。
- - **按钮区域** (`Row`):水平布局的按钮区域,包括 "取消" 和 "确定" 两个按钮。
- - **取消按钮**:点击时调用控制器的 `close()` 方法,关闭对话框。
- - **确定按钮**:点击时将选中的日期以毫秒形式保存到全局存储中,并关闭对话框。
-
5. **其他**:
- 、 - 使用常量 `CommonConstants.SPACE_12` 来设置布局元素之间的间距和内边距。
- - 使用 `$r('app.color.light_gray')` 和 `$r('app.color.primary_color')` 获取应用程序定义的颜色值,用于设置按钮的背景颜色。
运行截图:
三、CalorieStats
`CalorieStats` 组件用于展示用户的饮食摄入、运动消耗和推荐摄入量等信息。该组件包含一个名为 `remainCalorie` 的方法,用于计算剩余卡路里(即推荐摄入量减去饮食摄入加上运动消耗)。在 `build` 方法中,使用 `Row` 布局,将饮食摄入、剩余可摄入量和运动消耗的信息展示在同一行内。
在剩余可摄入量(即“还可以吃”按钮)的 `Stack` 中,使用 `Progress` 组件展示进度条,指示饮食摄入占推荐摄入量的比例。同时,通过 `StatsBuilder` 方法展示剩余可摄入量的卡路里数值及其推荐摄入量。此外,使用 `StatsBuilder` 方法分别展示饮食摄入和运动消耗的信息。
具体来说,`CalorieStats` 组件通过以下方式实现上述功能:
- 1. **定义方法**:
- - `remainCalorie` 方法:计算剩余卡路里,其公式为推荐摄入量减去饮食摄入加上运动消耗。
- 2. **布局设计**:
- - 在 `build` 方法中,使用 `Row` 布局将饮食摄入、剩余可摄入量和运动消耗的信息水平排列。
- - 剩余可摄入量部分采用 `Stack` 布局,其中包含一个 `Progress` 组件,用于显示饮食摄入占推荐摄入量的比例。
- 3. **信息展示**:
- - 通过 `StatsBuilder` 方法,展示剩余可摄入量的详细信息,包括具体的卡路里数值和推荐摄入量。
- 另外,使用 `StatsBuilder` 方法分别展示饮食摄入和运动消耗的具体数值,以提供用户全面的卡路里统计信息。
这种设计确保了 `CalorieStats` 组件能够以用户友好的方式展示关键的卡路里统计数据,并且通过合理的布局和进度条视觉化地表示摄入和消耗情况。
代码及其注释如下:
import { CommonConstants } from '../../common/constants/CommonConstants';
@Component
export default struct CalorieStats {
// 初始化饮食摄入、运动消耗和推荐摄入量
intake: number = 192; // 饮食摄入
expend: number = 150; // 运动消耗
recommend: number = CommonConstants.RECOMMEND_CALORIE; // 推荐摄入量
// 计算剩余可摄入卡路里
remainCalorie() {
return this.recommend - this.intake + this.expend;
}
// 构建UI布局
build() {
Row({ space: CommonConstants.SPACE_6 }) {
// 1. 饮食摄入
this.StatsBuilder({ label: '饮食摄入', value: this.intake });
// 2. 还可以吃
Stack() {
// 2.1. 进度条
Progress({
value: this.intake,
total: this.recommend,
type: ProgressType.Ring,
})
.width(120)
.style({ strokeWidth: CommonConstants.DEFAULT_10 })
.color($r('app.color.primary_color'));
// 2.2. 统计数据
this.StatsBuilder({
label: '还可以吃',
value: this.remainCalorie(),
tips: `推荐${this.recommend}`,
});
}
// 3. 运动消耗
this.StatsBuilder({ label: '运动消耗', value: this.expend });
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({ top: 30, bottom: 35 });
}
// 构建统计数据组件
@Builder
StatsBuilder($$: { label: string; value: number; tips?: string }) {
Column({ space: CommonConstants.SPACE_6 }) {
// 标签
Text($$.label)
.fontColor($r('app.color.gray'))
.fontWeight(CommonConstants.FONT_WEIGHT_600);
// 数值
Text($$.value.toFixed(0))
.fontSize(20)
.fontWeight(CommonConstants.FONT_WEIGHT_700);
// 提示信息(如果有)
if ($$.tips) {
Text($$.tips)
.fontSize(12)
.fontColor($r('app.color.light_gray'));
}
}
}
}
这段代码主要涉及以下几个知识点:
- 1. **组件定义与构建**:
- - 使用了 `@Component` 注解,表明 `CalorieStats` 是一个组件。
- - `CalorieStats` 结构体定义了三个属性 `intake`(摄入卡路里)、`expend`(消耗卡路里)、`recommend`(推荐摄入卡路里),并初始化了它们的默认值。
- 2. **方法定义**:
- - `remainCalorie()` 方法计算剩余可摄入卡路里,根据推荐摄入量、摄入量和消耗量计算出剩余的卡路里数。
- 3. **UI 构建**:
- - `build()` 方法用于构建用户界面(UI)。它使用了一系列 UI 组件和布局属性(如 `Row`、`Stack`、`Column`、`Text`、`Progress` 等),将数据以特定格式展示出来。
- - 在 `build()` 方法中,通过 `StatsBuilder` 方法构建了不同的统计数据项,并设置了相应的样式和布局。
- 4. **常量和样式管理**:
- - 使用了 `CommonConstants` 中定义的常量,如 `RECOMMEND_CALORIE`、`SPACE_6`、`DEFAULT_10` 等,用于统一管理样式、间距等参数,提高代码的可维护性和可读性。
- 5. **注释添加**:
- - 为了增强代码的可理解性,添加了详细的注释,解释了每个变量、方法和组件的作用和用途。
总体而言,这段代码展示了如何使用 TypeScript 和一个 UI 框架(假设是类似 Vue 或 React 的框架)来构建一个计算和展示卡路里摄入、消耗以及推荐摄入量的组件。通过结构化的方式管理数据和 UI,提高了代码的可维护性和复用性。
运行截图:
四、NutrientStats
NutrientStats 组件用于展示用户摄入的营养成分(碳水化合物、蛋白质和脂肪)以及推荐的摄入量。定义了以下属性:
- - `carbon`: 用户摄入的碳水化合物数量。
- - `protein`: 用户摄入的蛋白质数量。
- - `fat`: 用户摄入的脂肪数量。
- - `recommendCarbon`: 推荐的碳水化合物摄入量。
- - `recommendProtein`: 推荐的蛋白质摄入量。
- - `recommendFat`: 推荐的脂肪摄入量。
`build()` 方法用于构建组件的布局。在该方法中,使用 `Row` 布局将三个营养成分(碳水化合物、蛋白质和脂肪)放置在一行,并设置了适当的间距。每个营养成分通过 `StatsBuilder` 实例进行展示,传入相应的标签、值、推荐值和颜色。
`StatsBuilder` 方法负责构建每个营养成分的展示部分。在该方法中,首先创建一个 `Column` 布局,然后在其中创建一个 `Stack` 布局,用于放置环形进度条和两个文本。环形进度条的值表示当前营养成分的摄入量,总值为推荐摄入量,类型为 `ProgressType.Ring`。进度条的宽度、线宽和颜色由参数指定。
接下来,创建两个文本标识:一个显示“摄入推荐”,另一个显示当前摄入量与推荐摄入量的比例。最后,创建一个文本显示营养成分的名称,并设置字体大小和颜色。整体布局的宽度、对齐方式和内边距也在 `build()` 方法中进行了设置。
代码如下:
import { CommonConstants } from '../../common/constants/CommonConstants';
// 定义 NutrientStats 组件,用于展示营养成分的摄入量和推荐量
@Component
export default struct NutrientStats {
// 默认营养成分的摄入量
carbon: number = 23;
protein: number = 9;
fat: number = 7;
// 推荐的营养成分摄入量,使用常量定义
recommendCarbon: number = CommonConstants.RECOMMEND_CARBON;
recommendProtein: number = CommonConstants.RECOMMEND_PROTEIN;
recommendFat: number = CommonConstants.RECOMMEND_FAT;
// 构建方法,用于生成组件的布局
build() {
Row({ space: CommonConstants.SPACE_6 }) {
// 调用 StatsBuilder 方法,分别展示碳水化合物、蛋白质和脂肪的营养成分情况
this.StatsBuilder({
label: '碳水化合物',
value: this.carbon,
recommend: this.recommendCarbon,
color: $r('app.color.carbon_color') // 碳水化合物的颜色
});
this.StatsBuilder({
label: '蛋白质',
value: this.protein,
recommend: this.recommendProtein,
color: $r('app.color.protein_color') // 蛋白质的颜色
});
this.StatsBuilder({
label: '脂肪',
value: this.fat,
recommend: this.recommendFat,
color: $r('app.color.fat_color') // 脂肪的颜色
});
}
.width('100%') // 设置整行的宽度为100%
.justifyContent(FlexAlign.SpaceEvenly) // 水平分布排列元素
.padding({ top: 30, bottom: 35 }); // 设置上下内边距
}
// StatsBuilder 方法,用于构建单个营养成分的展示部分
@Builder StatsBuilder($$:{ label: string, value: number, recommend: number, color: ResourceStr }) {
Column({ space: CommonConstants.SPACE_6 }) {
Stack() {
// 使用 Progress 组件展示环形进度条,显示当前摄入量与推荐摄入量
Progress({
value: $$.value,
total: $$.recommend,
type: ProgressType.Ring // 环形进度条类型
})
.width(95) // 进度条宽度
.style({ strokeWidth: CommonConstants.DEFAULT_6 }) // 进度条线宽
.color($$.color); // 进度条颜色
Column({ space: CommonConstants.SPACE_6 }) {
// 展示“摄入推荐”文本
Text('摄入推荐')
.fontSize(12)
.fontColor($r('app.color.gray')); // 文本颜色
// 显示当前摄入量和推荐摄入量的比例
Text(`${$$.value.toFixed(0)}/${$$.recommend.toFixed(0)}`)
.fontSize(18)
.fontWeight(CommonConstants.FONT_WEIGHT_600); // 设置字体粗细
}
}
// 显示营养成分名称和单位(克)
Text(`${$$.label}(克)`)
.fontSize(12)
.fontColor($r('app.color.light_gray')); // 设置字体颜色
}
}
}
这段代码展示了一个典型的 Vue.js 组件的实现,主要涉及以下几个知识点和技术:
- 1. **Vue 组件结构**:
- - 使用 `@Component` 装饰器定义组件,利用 `struct` 关键字创建结构体形式的组件。
- - 组件包含默认的营养成分摄入量(碳水化合物、蛋白质、脂肪)和推荐的营养成分摄入量。
- 2. **布局和样式**:
- - 使用 `Row` 和 `Column` 组件来管理布局,以及分隔子组件之间的间距。
- - 使用 `Stack` 组件创建层叠效果,用于显示环形进度条和相关文本。
- 3. **进度条和数据展示**:
- - 使用自定义的 `Progress` 组件展示环形进度条,用于比较当前摄入量与推荐摄入量。
- - 在进度条旁边显示当前摄入量和推荐摄入量的比例,以及相应的营养成分名称和单位。
- 4. **样式和主题**:
- - 引用主题变量(如 `$r('app.color.carbon_color')`)来设置组件的颜色和样式,使得组件在不同主题下能够保持一致的外观。
- 5. **方法和逻辑**:
- - 使用 `@Builder` 装饰器定义 `StatsBuilder` 方法,用于构建和组织单个营养成分的展示部分,提高代码的模块化和复用性。
- - 在 `build` 方法中调用 `StatsBuilder` 方法来动态生成多个营养成分的展示区域。
总体来说,这段代码展示了如何利用 Vue.js 的组件化思想和相关的生命周期方法、样式管理以及模块化开发,构建一个能够动态展示营养成分摄入情况的用户界面。
运行截图:
总结
通过本文详细介绍了一个名为StatsCard的统计卡片组件的设计和实现细节,其中包括三个主要组件:DatePickDialog、CalorieStats和NutrientStats。
StatsCard作为主组件,实现了以下功能:
- 1. **DatePickDialog组件**:用于选择日期,并在界面上显示用户所选的日期。
- 2. **CalorieStats组件**:展示用户的饮食摄入、剩余可摄入以及运动消耗的热量统计数据。
- 3. **NutrientStats组件**:展示用户摄入的碳水化合物、蛋白质和脂肪的详细统计数据。
每个组件通过统一的设计风格和模块化的开发方式,有效实现了功能模块的分离与复用,使得StatsCard能够在用户界面上动态展示并管理重要的健康数据统计信息。