HarmonyOS5 運動健康app(一):健康飲食(附代碼)

一、核心數據模型設計

代碼通過兩個接口構建了飲食管理的基礎數據結構:

interface footItem {name: string; // 營養名稱(蛋白質/碳水/脂肪)weight: number; // 重量(克)
}interface DietItem {name: string; // 食物名稱image: string; // 圖片路徑(如app.media.mantou)weight: number; // 單份重量(克)calorie: number; // 單份卡路里count: number; // 食用數量nengliang: string; // 主要營養素類型
}
  • 營養元素模型(footItem):將蛋白質、碳水、脂肪抽象為基礎單元,用于統計每日攝入量。
  • 食物模型(DietItem):每個食物對象包含物理屬性(重量、卡路里)和營養屬性(nengliang),如:
{ name: '雞蛋', image: 'app.media.egg', weight: 13, calorie: 200, count: 0, nengliang: '蛋白質' }

其中nengliang字段建立了食物與基礎營養素的映射關系,為后續營養統計提供依據。

二、主組件架構:Index組件的狀態與布局
@Entry
@Component
export struct Index {@State progressIndex: number = 0 // 總卡路里@State dbzIndex: number = 0 // 總蛋白質@State tsIndex: number = 0 // 總碳水@State zfIndex: number = 0 // 總脂肪// 頭部統計組件@Buildertoubu() {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)}// 營養素統計行Row() {ForEach(footData, (item) => {Column() {Text(this.getItemWeight(item).toString()).fontSize(18).fontColor('#333')Text(item.name).fontSize(14).fontColor('#666')}.width('30%')})}}.padding({ top: 20, bottom: 15 }).width('100%')}// 營養素與狀態映射private getItemWeight(item: footItem): number {switch (item.name) {case '蛋白質': return this.dbzIndexcase '碳水': return this.tsIndexcase '脂肪': return this.zfIndexdefault: return 0}}build() {Column({ space: 15 }) {this.toubu()Text('飲食內容').fontSize(20).margin({ left: 20 })List() {ForEach(dietData, (item) => {ListItem() { foods({ item, progressIndex: this.progressIndex, ... }) }})}}.width('100%').padding({ left: 10, right: 10 })}
}
  • 狀態管理:通過@State定義四大核心狀態,分別追蹤總卡路里和三類營養素攝入量,形成數據中樞。
  • 頭部組件(toubu)
    • 環形進度條使用Progress組件,以20000kcal為目標值,綠色進度隨progressIndex動態變化;
    • 營養素統計行通過ForEach遍歷footData,將dbzIndex等狀態映射為界面數值,實現"蛋白質:18g"等展示效果。

三、可復用組件:foods組件的交互邏輯
@Reusable
@Component
export struct 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 * amountswitch (this.item.nengliang) {case '蛋白質': this.dbzIndex += weightChangecase '碳水': this.tsIndex += weightChangecase '脂肪': this.zfIndex += weightChange}}build() {Row() {Image($r(this.item.image)).width(60).height(60).borderRadius(8)Column() {Text(this.item.name).fontSize(16).fontWeight(FontWeight.Bold)Text(`${this.item.weight} 克`).fontSize(14).fontColor('#777')}.width('40%')Column() {Text(`${this.item.calorie * this.item.count} 卡`).fontSize(16)Row() {Text('-').onClick(() => {if (this.item.count > 0) {this.item.count--; this.ifjiajian = falsethis.calorieNUm(); this.weightNUm()}})Text(`${this.item.count}`).width(30).textAlign(TextAlign.Center)Text('+').onClick(() => {this.item.count++; this.ifjiajian = truethis.calorieNUm(); this.weightNUm()})}.width(90)}.width('40%')}.width('100%').padding({ left: 10, right: 10 })}
}
  • 狀態綁定:通過@Link實現與主組件狀態的雙向同步,點擊"+/-"按鈕時,progressIndex和營養素狀態會實時更新。
  • 交互邏輯
    • ifjiajian標記操作類型,增加時calorieNUm()計算正卡路里值,減少時計算負值;
    • weightNUm()根據nengliang屬性(如"蛋白質")更新對應營養素總量,1份食物默認增加13克重量(與item.weight一致)。

四、數據流轉與業務閉環
  1. 用戶操作:點擊食物卡片的"+"按鈕 → item.count自增 → ifjiajian設為true
  2. 數據計算
    • calorieNUm()計算新增卡路里(如雞蛋200卡×1份),累加到progressIndex
    • weightNUm()根據nengliang(蛋白質)計算13克重量,累加到dbzIndex
  1. 界面更新:主組件的環形進度條和營養素數值通過狀態響應式機制自動刷新,形成"操作-計算-展示"的閉環。

五、附:代碼
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 // 總脂肪// 頭部組件@Buildertoubu() {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)}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83758.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83758.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83758.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MQ選型及RocketMQ架構總覽

一、什么是MQ MQ(MessageQueue) Message(消息):消息是在不同進程之間傳遞的數據,這些進程可以在同一臺機器上,也可以在不同的機器上。 Queue(隊列):隊列原意是指一種具有FIFO&#…

python與java的區別

java老程序員來學習python了,記錄一下兩種類型語言的區別: Python與Java變量類型對比 python里面定義變量不需要指定變量的數據類型,并且是可以修改成其他類型java里面定義變量要指定變量的數據類型,指定以后不可以修改成其他數據…

固件簽名技術深度解析:HSM模塊如何守護設備安全,CAS系統如何賦能產業升級

引言:數字時代的固件安全危機 在萬物互聯的今天,全球設備固件安全事件頻發:某汽車品牌因固件漏洞導致百萬車輛被遠程控制,某醫療設備廠商因固件篡改引發數據泄露,某工業控制系統因非法固件升級造成生產線癱瘓……這些…

修改Typora快捷鍵

代碼 的默認快捷鍵為: 這對我來說不太友好,太難按了,而且我電腦右邊的Ctrl鍵壞了,這意味著我只能一個左手去按這3個鍵的組合,這更是難上加難了,于是想到改一下快捷鍵,代碼塊 是Ctrl Shift K&…

Bellman-Ford算法(詳解版)

Bellman-Ford算法 Bellman-Ford算法是用來解決,對于有負權的圖的**單源最短路徑**.因為DJ算法不可以解決對于負權的圖,所以使用這個算法來求解.但是依舊不可以有負回路.因為負回路就沒有存在單源最短路徑這一說. BF的另一個重要的用途就是用來檢測**是不是存在負回路** 思路…

《HarmonyOSNext的ForEach數組渲染の核心玩法與避坑指南》

《HarmonyOSNext教學寶典:ForEach數組渲染全攻略與性能優化》 #HarmonyOS開發 #ArkTS實戰 #組件解析 🎯 ForEach組件完全指南:數組循環渲染核心機制 舉個栗子🌰: ForEach相當于智能印刷機,將數組元素自動轉…

單片機 - STM32F407 ADC 模式詳解:單次轉換、連續轉換、掃描模式、非掃描模式

STM32F407 ADC 模式詳解:單次轉換、連續轉換、掃描模式、非掃描模式 前言 在 STM32F407 中,ADC(模數轉換器)模塊常用于采集模擬信號,比如讀取光敏電阻、電壓、電流、溫度傳感器等。STM32 的 ADC 模式較多&#xff0c…

開源模型應用落地-工具使用篇-從零開始搭建Qdrant Web UI-可視化管理工具-Windows(十)

一、前言 Qdrant 是一個高性能的向量搜索引擎,廣泛應用于相似性搜索、推薦系統和大規模數據檢索等場景。雖然其原生 API 提供了強大的功能,但對于開發者和運維人員來說,缺乏直觀的可視化界面常常增加了使用門檻。為了解決這一問題&#xff0c…

高頻交易技術:訂單簿分析與低延遲架構——從Level 2數據挖掘到FPGA硬件加速的全鏈路解決方案

高頻交易技術:訂單簿分析與低延遲架構——從Level 2數據挖掘到FPGA硬件加速的全鏈路解決方案 一、引言:高頻交易的技術本質 1.1 速度即利潤的微觀戰場 數據揭示:據NYSE實測,每降低1微秒延遲可獲得年化$700-1500萬套利窗口&#…

基于生成對抗網絡(GAN)的圖像生成與編輯:原理、應用與實踐

前言 生成對抗網絡(GAN)是近年來深度學習領域中最具影響力的技術之一。自2014年由Ian Goodfellow等人首次提出以來,GAN已經在圖像生成、圖像編輯、風格轉換等多個領域取得了令人矚目的成果。GAN的核心思想是通過生成器(Generator&…

pytorch基本運算-梯度運算:requires_grad_(True)和backward()

引言 前序學習進程中,已經對pytorch基本運算中的求導進行了基礎討論,相關文章鏈接為: 導數運算pytorch基本運算-導數和f-string-CSDN博客 實際上,求導是微分的進一步計算,要想求導的前一步其實是計算微分&#xff1…

idea64.exe.vmoptions配置

這個idea64.exe.vmoptions文件是用于配置 IntelliJ IDEA(64位版本)運行時的 Java 虛擬機(JVM)參數。這些參數直接影響到 IDEA 的性能、內存使用、調試能力和行為。 下面是對文件中每一行配置的詳細解讀: -Xms2048m 作…

齊次變換矩陣相乘的復合變換:左乘與右乘的深度解析

在三維幾何變換中,齊次變換矩陣相乘是實現復雜變換的核心方法。本文將通過一個包含四個變換步驟的完整示例,深入探討齊次變換矩陣左乘和右乘的區別,并結合 Python sympy 庫的代碼實現,詳細闡述變換過程和結果差異。 二維齊次坐標的旋轉變換 在二維齊次坐標系中,一個點可以…

5g LDPC編譯碼-LDPC編碼

目錄 1、LDPC編碼基礎知識 2、5g的LDPC編碼 2.1 LDPC分塊: 2.2 LDCP編碼 2.3 校驗位的產生 1、LDPC編碼基礎知識 LDPC屬于線性分組碼,線性分組碼的基本知識如下: 編碼后的碼字是由初始二進制序列與生成矩陣在二進制域相乘后得到,生成矩陣與校驗矩陣,校驗矩陣與編碼后…

OpenVINO使用教程--resnet分類模型部署

OpenVINO使用教程--resnet分類模型部署 本節內容模型準備推理測試分析&總結本節內容 OpenVINO 根據AI技術類型將部署任務分成傳統模型模型部署和生成式AI模型部署,傳統模型指的是各種CNN小模型,這部分部署只需要OpenVINO包,具體安裝教程可以參考之前的章節:OpenVINO環境…

無字母數字webshell的命令執行

在Web安全領域,WebShell是一種常見的攻擊手段,通過它攻擊者可以遠程執行服務器上的命令,獲取敏感信息或控制系統。而無字母數字WebShell則是其中一種特殊形式,通過避免使用字母和數字字符,來繞過某些安全機制的檢測。 …

C++斯特林數在C++中的數學理論與計算實現1

一、 斯特林數概述 1.1 組合數學中的核心地位 斯特林數(Stirling Numbers)是組合數學中連接排列、組合與分劃問題的核心工具,分為兩類: 第一類斯特林數(Stirling Numbers of the First Kind)&#xff1a…

[C++] STL大家族之<map>(字典)容器(附洛谷)

map-目錄 使用方法頭文件與聲明定義基本操作 使用方法 頭文件與聲明定義 頭文件是: #include <map>我們這樣聲明一個字典: map</*key_type*/, /*value_type*/> /*map_name*/; // 例子: map<int, char> mp;這里稍作解釋: key_type是你每個鍵值對中的鍵的…

使用 Flutter 在 Windows 平臺開發 Android 應用

以下是完整的開發流程&#xff0c;包括環境搭建、代碼實現和應用發布&#xff0c;幫助你開發一個具有地圖顯示、TCP 通信功能的 Android 應用。 一、環境搭建 1. 安裝 Flutter SDK 從 Flutter 官網 下載最新穩定版 SDK解壓到本地目錄&#xff08;如 D:\flutter&#xff09;添…

【模板】埃拉托色尼篩法(埃氏篩)

一、算法簡介 在數論與編程競賽中&#xff0c;求解 [ 1 , n ] [1,n] [1,n] 范圍內的所有質數是常見的基礎問題。埃拉托色尼篩法&#xff08;Sieve of Eratosthenes&#xff09; 是一種古老而高效的算法&#xff0c;可以在 O ( n log ? log ? n ) O(n \log \log n) O(nlogl…