HarmonyOS5 運(yùn)動(dòng)健康app(一): 健康飲食(附代碼)
飲食管理應(yīng)用架構(gòu)設(shè)計(jì)文檔
一、核心數(shù)據(jù)模型設(shè)計(jì)
1. 營(yíng)養(yǎng)元素模型 (footItem)
interface footItem { name: string; // 營(yíng)養(yǎng)名稱(chēng)(蛋白質(zhì)/碳水/脂肪) weight: number; // 重量(克) } ### 2. 食物模型 (`DietItem`) ```typescript interface DietItem { name: string; // 食物名稱(chēng) image: string; // 圖片路徑(如app.media.mantou) weight: number; // 單份重量(克) calorie: number; // 單份卡路里 count: number; // 食用數(shù)量 nengliang: string; // 主要營(yíng)養(yǎng)素類(lèi)型 }
設(shè)計(jì)說(shuō)明:
footItem 將蛋白質(zhì)、碳水、脂肪抽象為基礎(chǔ)單元 DietItem 包含物理屬性+營(yíng)養(yǎng)屬性,nengliang字段建立食物與營(yíng)養(yǎng)素的映射關(guān)系二、主組件架構(gòu):Index組件
狀態(tài)管理
@State progressIndex: number = 0 // 總卡路里 @State dbzIndex: number = 0 // 總蛋白質(zhì) @State tsIndex: number = 0 // 總碳水 @State zfIndex: number = 0 // 總脂肪
頭部統(tǒng)計(jì)組件 (toubu)
@Builder toubu() { Column({ space: 15 }) { // 環(huán)形卡路里進(jìn)度條 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) } // 營(yíng)養(yǎng)素統(tǒng)計(jì)行 Row() { ForEach(footData, (item) => { Column() { Text(this.getItemWeight(item).toString()).fontSize(18) Text(item.name).fontSize(14) }.width('30%') }) } } }
功能特點(diǎn):
環(huán)形進(jìn)度條目標(biāo)值20000kcal 營(yíng)養(yǎng)素統(tǒng)計(jì)行實(shí)時(shí)顯示三類(lèi)營(yíng)養(yǎng)素?cái)z入量三、可復(fù)用組件:foods組件
核心屬性
@State ifjiajian: boolean = false // 操作類(lèi)型(增減) @Prop item: DietItem // 食物對(duì)象(只讀) @Link progressIndex: number // 雙向綁定總卡路里 @Link dbzIndex: number // 雙向綁定蛋白質(zhì)
關(guān)鍵方法
// 卡路里計(jì)算 calorieNUm() { const num = this.ifjiajian ? this.item.calorie * this.item.count : -this.item.calorie * (this.item.count + 1) this.progressIndex += num } // 營(yíng)養(yǎng)素計(jì)算 weightNUm() { const amount = this.ifjiajian ? this.item.count : -(this.item.count + 1) const weightChange = 13 * amount switch(this.item.nengliang) { case '蛋白質(zhì)': this.dbzIndex += weightChange case '碳水': this.tsIndex += weightChange case '脂肪': this.zfIndex += weightChange } }
四、數(shù)據(jù)流轉(zhuǎn)閉環(huán)
用戶(hù)操作 → 點(diǎn)擊"+"按鈕
item.count++ ifjiajian = true數(shù)據(jù)計(jì)算:
calorieNUm()計(jì)算新增卡路里 weightNUm()更新對(duì)應(yīng)營(yíng)養(yǎng)素界面更新:
環(huán)形進(jìn)度條自動(dòng)刷新 營(yíng)養(yǎng)素?cái)?shù)值實(shí)時(shí)更新五、完整代碼
點(diǎn)擊查看完整實(shí)現(xiàn)interface footItem { name: string; // 營(yíng)養(yǎng)名稱(chēng) weight: number; // 重量 } interface DietItem { name: string; // 食物名稱(chēng) image: string; // 食物圖片路徑(本地或網(wǎng)絡(luò),這里用占位示意) weight: number; // 重量 calorie: number; // 卡路里 count: number; // 食用數(shù)量 nengliang: string; // 營(yíng)養(yǎng)名稱(chēng)(蛋白質(zhì)、脂肪、碳水) } const footData: footItem[] = [ { name: '蛋白質(zhì)', weight: 0 }, { name: '碳水', weight: 0 }, { name: '脂肪', weight: 0 }, ]; const dietData: DietItem[] = [ { name: '饅頭', image: 'app.media.mantou', weight: 13, calorie: 100, count: 0, nengliang: '蛋白質(zhì)' }, { name: '油條', image: 'app.media.youtiao', weight: 13, calorie: 200, count: 0, nengliang: '脂肪' }, { name: '豆?jié){', 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: '蛋白質(zhì)' }, ]; @Entry @Component export struct Index { @State progressIndex: number = 0 // 進(jìn)度條進(jìn)度(總大卡數(shù)) @State dbzIndex: number = 0 // 總蛋白質(zhì) @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) } // 獲取對(duì)應(yīng)的營(yíng)養(yǎng)值 private getItemWeight(item: footItem): number { switch (item.name) { case '蛋白質(zhì)': return this.dbzIndex; case '碳水': return this.tsIndex; case '脂肪': return this.zfIndex; default: return 0; } } build() { Column({ space: 15 }) { this.toubu() Text('飲食內(nèi)容') .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 }) } } // 飲食內(nèi)容組件 @Reusable @Component export struct foods { @State ifjiajian: boolean = false @Prop item: DietItem @Link progressIndex: number @Link dbzIndex: number @Link tsIndex: number @Link zfIndex: number // 統(tǒng)計(jì)大卡數(shù) calorieNUm() { let num = this.ifjiajian ? this.item.calorie * this.item.count : -this.item.calorie * (this.item.count + 1); this.progressIndex += num; } // 統(tǒng)計(jì)能量 weightNUm() { const amount = this.ifjiajian ? this.item.count : -(this.item.count + 1); const weightChange = 13 * amount; switch (this.item.nengliang) { case '蛋白質(zhì)': 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) } }
```
相關(guān)知識(shí)
HarmonyOS5 運(yùn)動(dòng)健康app(一):健康飲食(附代碼)
飲食熱量app開(kāi)發(fā)源碼 健康飲食運(yùn)動(dòng)減脂app小程序設(shè)計(jì)制作開(kāi)發(fā)源碼出售
春運(yùn)全國(guó)健康碼百度APP怎么申領(lǐng)?附流程圖解
健康運(yùn)動(dòng)健身系統(tǒng)app開(kāi)發(fā)
小米運(yùn)動(dòng)健康app怎么記錄飲食
華為運(yùn)動(dòng)健康app如何升級(jí) 華為運(yùn)動(dòng)健康app?
支付寶APP健康碼全國(guó)一碼通行怎么弄?附申請(qǐng)流程
湖北健康碼app
河南健康碼app
下載安裝華為運(yùn)動(dòng)健康A(chǔ)pp
網(wǎng)址: HarmonyOS5 運(yùn)動(dòng)健康app(一): 健康飲食(附代碼) http://www.u1s5d6.cn/newsview1711827.html
推薦資訊
- 1發(fā)朋友圈對(duì)老公徹底失望的心情 12775
- 2BMI體重指數(shù)計(jì)算公式是什么 11235
- 3補(bǔ)腎吃什么 補(bǔ)腎最佳食物推薦 11199
- 4性生活姿勢(shì)有哪些 盤(pán)點(diǎn)夫妻性 10428
- 5BMI正常值范圍一般是多少? 10137
- 6在線(xiàn)基礎(chǔ)代謝率(BMR)計(jì)算 9652
- 7一邊做飯一邊躁狂怎么辦 9138
- 8從出汗看健康 出汗透露你的健 9063
- 9早上怎么喝水最健康? 8613
- 10五大原因危害女性健康 如何保 7828
- 今日水素:陽(yáng)臺(tái)菜園,居家種出健康芽菜指南
- 運(yùn)動(dòng)女孩的休閑穿搭
- 《居家健康監(jiān)測(cè)證明》可在“隨申辦”在線(xiàn)開(kāi)
- 【便民提示】在線(xiàn)開(kāi)具“居家健康監(jiān)測(cè)證明”
- 健身休閑館如何經(jīng)營(yíng)管理
- 這個(gè)集運(yùn)動(dòng)、休閑、時(shí)尚為一體的運(yùn)動(dòng)品牌進(jìn)
- 知名運(yùn)動(dòng)休閑服裝品牌
- 江北新區(qū)兩案例入選省級(jí)居家社區(qū)養(yǎng)老服務(wù)典
- 康健園·戰(zhàn)“疫”|慢性病患者如何做好居家
- 北京啟明康健休閑健身中心 (北京市豐臺(tái)區(qū)