HarmonyOS5 运动健康app(一):健康饮食(附代码)
2025-06-28 19:42:37
108次阅读
0个评论
饮食管理应用架构设计文档
一、核心数据模型设计
1. 营养元素模型 (footItem
)
interface footItem {
name: string; // 营养名称(蛋白质/碳水/脂肪)
weight: number; // 重量(克)
}
### 2. 食物模型 (`DietItem`)
```typescript
interface DietItem {
name: string; // 食物名称
image: string; // 图片路径(如app.media.mantou)
weight: number; // 单份重量(克)
calorie: number; // 单份卡路里
count: number; // 食用数量
nengliang: string; // 主要营养素类型
}
设计说明:
footItem
将蛋白质、碳水、脂肪抽象为基础单元DietItem
包含物理属性+营养属性,nengliang
字段建立食物与营养素的映射关系
二、主组件架构:Index组件
状态管理
@State progressIndex: number = 0 // 总卡路里
@State dbzIndex: number = 0 // 总蛋白质
@State tsIndex: number = 0 // 总碳水
@State zfIndex: number = 0 // 总脂肪
头部统计组件 (toubu
)
@Builder
toubu() {
Column({ space: 15 }) {
// 环形卡路里进度条
Stack() {
Progress({ value: this.progressIndex, total: 20000, type: ProgressType.Ring })
.width(90).height(90).style({ strokeWidth: 10 })
Text(`${this.progressIndex} kcal`).fontSize(14).fontWeight(FontWeight.Bold)
}
// 营养素统计行
Row() {
ForEach(footData, (item) => {
Column() {
Text(this.getItemWeight(item).toString()).fontSize(18)
Text(item.name).fontSize(14)
}.width('30%')
})
}
}
}
功能特点:
- 环形进度条目标值20000kcal
- 营养素统计行实时显示三类营养素摄入量
三、可复用组件:foods组件
核心属性
@State ifjiajian: boolean = false // 操作类型(增减)
@Prop item: DietItem // 食物对象(只读)
@Link progressIndex: number // 双向绑定总卡路里
@Link dbzIndex: number // 双向绑定蛋白质
关键方法
// 卡路里计算
calorieNUm() {
const num = this.ifjiajian
? this.item.calorie * this.item.count
: -this.item.calorie * (this.item.count + 1)
this.progressIndex += num
}
// 营养素计算
weightNUm() {
const amount = this.ifjiajian ? this.item.count : -(this.item.count + 1)
const weightChange = 13 * amount
switch(this.item.nengliang) {
case '蛋白质': this.dbzIndex += weightChange
case '碳水': this.tsIndex += weightChange
case '脂肪': this.zfIndex += weightChange
}
}
四、数据流转闭环
-
用户操作 → 点击"+"按钮
item.count++
ifjiajian = true
-
数据计算:
calorieNUm()
计算新增卡路里weightNUm()
更新对应营养素
-
界面更新:
- 环形进度条自动刷新
- 营养素数值实时更新
五、完整代码
点击查看完整实现
interface footItem {
name: string; // 营养名称
weight: number; // 重量
}
interface DietItem {
name: string; // 食物名称
image: string; // 食物图片路径(本地或网络,这里用占位示意)
weight: number; // 重量
calorie: number; // 卡路里
count: number; // 食用数量
nengliang: string; // 营养名称(蛋白质、脂肪、碳水)
}
const footData: footItem[] = [
{ name: '蛋白质', weight: 0 },
{ name: '碳水', weight: 0 },
{ name: '脂肪', weight: 0 },
];
const dietData: DietItem[] = [
{ name: '馒头', image: 'app.media.mantou', weight: 13, calorie: 100, count: 0, nengliang: '蛋白质' },
{ name: '油条', image: 'app.media.youtiao', weight: 13, calorie: 200, count: 0, nengliang: '脂肪' },
{ name: '豆浆', image: 'app.media.doujiang', weight: 13, calorie: 300, count: 0, nengliang: '碳水' },
{ name: '稀饭', image: 'app.media.xifan', weight: 13, calorie: 300, count: 0, nengliang: '碳水' },
{ name: '鸡蛋', image: 'app.media.egg', weight: 13, calorie: 200, count: 0, nengliang: '蛋白质' },
];
@Entry
@Component
export struct Index {
@State progressIndex: number = 0 // 进度条进度(总大卡数)
@State dbzIndex: number = 0 // 总蛋白质
@State tsIndex: number = 0 // 总碳水
@State zfIndex: number = 0 // 总脂肪
// 头部组件
@Builder
toubu() {
Column({ space: 15 }) {
Stack() {
Progress({
value: this.progressIndex,
total: 20000,
type: ProgressType.Ring
})
.width(90)
.height(90)
.style({ strokeWidth: 10 })
.color('#4CD964')
.backgroundColor('#e0e0e0');
Text(`${this.progressIndex} kcal`)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.margin({ top: 5 })
}
Row() {
ForEach(footData, (item: footItem) => {
Column() {
Text(this.getItemWeight(item).toString())
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#333')
Text(item.name)
.fontSize(14)
.fontColor('#666')
}
.width('30%')
}, (item: footItem) => JSON.stringify(item))
}
}
.padding({ top: 20, bottom: 15 })
.width('100%')
.alignItems(HorizontalAlign.Center)
}
// 获取对应的营养值
private getItemWeight(item: footItem): number {
switch (item.name) {
case '蛋白质':
return this.dbzIndex;
case '碳水':
return this.tsIndex;
case '脂肪':
return this.zfIndex;
default:
return 0;
}
}
build() {
Column({ space: 15 }) {
this.toubu()
Text('饮食内容')
.fontSize(20)
.fontColor('#555')
.width('100%')
.margin({ left: 20 })
List({ space: 10 }) {
ForEach(dietData, (item: DietItem) => {
ListItem() {
foods({
item: item,
progressIndex: this.progressIndex,
dbzIndex: this.dbzIndex,
tsIndex: this.tsIndex,
zfIndex: this.zfIndex
})
}
}, (item: DietItem) => JSON.stringify(item))
}
}
.width('100%')
.padding({ left: 10,right: 10 })
}
}
// 饮食内容组件
@Reusable
@Component
export struct foods {
@State ifjiajian: boolean = false
@Prop item: DietItem
@Link progressIndex: number
@Link dbzIndex: number
@Link tsIndex: number
@Link zfIndex: number
// 统计大卡数
calorieNUm() {
let num = this.ifjiajian ?
this.item.calorie * this.item.count :
-this.item.calorie * (this.item.count + 1);
this.progressIndex += num;
}
// 统计能量
weightNUm() {
const amount = this.ifjiajian ? this.item.count : -(this.item.count + 1);
const weightChange = 13 * amount;
switch (this.item.nengliang) {
case '蛋白质':
this.dbzIndex += weightChange;
break;
case '碳水':
this.tsIndex += weightChange;
break;
case '脂肪':
this.zfIndex += weightChange;
break;
}
}
build() {
Row() {
Image($r(this.item.image))
.width(60)
.height(60)
.borderRadius(8)
Column({ space: 6 }) {
Text(this.item.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
Text(`${this.item.weight} 克`)
.fontSize(14)
.fontColor('#777')
}
.width('40%')
.alignItems(HorizontalAlign.Start)
Column({ space: 6 }) {
Text(`${this.item.calorie * this.item.count} 卡`)
.fontSize(16)
.fontColor('#555')
Row() {
Text('-')
.fontSize(20)
.width(25)
.height(25)
.textAlign(TextAlign.Center)
.borderRadius(4)
.border({ width: 1, color: '#ccc' })
.onClick(() => {
if (this.item.count > 0) {
this.item.count--;
this.ifjiajian = false;
this.calorieNUm();
this.weightNUm();
}
})
Text(`${this.item.count}`)
.fontSize(16)
.width(30)
.textAlign(TextAlign.Center)
Text('+')
.fontSize(20)
.width(25)
.height(25)
.textAlign(TextAlign.Center)
.borderRadius(4)
.border({ width: 1, color: '#ccc' })
.onClick(() => {
this.item.count++;
this.ifjiajian = true;
this.calorieNUm();
this.weightNUm();
})
}
.justifyContent(FlexAlign.SpaceAround)
.width(90)
}
.width('40%')
.alignItems(HorizontalAlign.Center)
}
.width('100%')
.padding({ left: 10, right: 10 })
.justifyContent(FlexAlign.SpaceBetween)
}
}
```00
- 0回答
- 0粉丝
- 0关注
相关话题
- HarmonyOS5 运动健康app(二):健康跑步(附代码)
- HarmonyOS5 运动健康app(三):健康睡眠(附代码)
- HarmonyOS5 购物商城app(一):商品展示(附代码)
- HarmonyOS5 音乐播放器app(一):歌曲展示与收藏功能(附代码)
- HarmonyOS5 儿童画板app:手绘写字(附代码)
- HarmonyOS5 购物商城app(二):购物车与支付(附代码)
- 【待更新】OpenHarmony——应用健康饮食助手
- 纯血HarmonyOS5 打造小游戏实践:扫雷(附源文件)
- ArkUI-X跨平台技术落地-华为运动健康(一)
- 鸿蒙HarmonyOS 5小游戏实践:记忆翻牌(附:源代码)
- 纯血HarmonyOS5 打造小游戏实践:绘画板(附源文件)
- HarmonyOS 5 多端适配原理与BreakpointSystem工具类解析:附代码
- 鸿蒙HarmonyOS 5小游戏实践:数字记忆挑战(附:源代码)
- 鸿蒙HarmonyOS 5小游戏实践:打砖块游戏(附:源代码)
- 鸿蒙HarmonyOS 5 小游戏实践:数字华容道(附:源代码)