用 HarmonyOS ArkUI 来开发一个健康饮食应用

news2024/12/23 5:21:40

本文演示如果在DevEco Studio 3里面,用HarmonyOS的ArkUI来开发一个健康饮食应用。体验HarmonyOS 3最新API 9!

获取HarmonyOS应用

HarmonyOS的ArkUI来开发一个健康饮食的ArkUI程序“ArkUIHealthyDiet”,基础代码已经有了[1],个人只需要在基础代码上稍作修改,就能运行了。

通过DevEco Studio 3导入应用

有关DevEco Studio 3的安装配置,可以参考前文《玩转HarmonyOS 3必装DevEco Studio 3,注意避弹[2]》这里就不在赘述。

首选是打开DevEco Studio 3,可以看到如下界面。

点击“Open Project”来导入我们实行装备好的ArkUI程序“ArkUIHealthyDiet”。

导入程序之后,就能在该程序基础上进行代码开发、运行。

通过DevEco Studio 3创建应用

如果想从0开始学习ArkUI,体验完整的HarmonyOS的开发过程,那么建议跟随本文一起来开启ArkUI开发之旅吧。

首选是打开DevEco Studio 3,可以看到如下界面。

点击“Create Project”来创建ArkUI程序“ArkUIHealthyDiet”。

选择模板

选择空模板Empty Ability,点击“Next”执行下一步。

配置项目

配置项目信息,重要是以下圈中部分。其他配置按照默认配置即可。点击“Finish”执行下一步。

运行HarmonyOS应用

打开Device Manager

登入华为账号

点击“Sign In”登入个人注册的华为账号。如果没有,则参考本文最后的链接进行注册。

启动远程模拟器

运行应用

点击下命的三角形按钮以启动应用

应用运行效果图如下。

完善应用

接下来是进入正题,开始我们的健康饮食应用的核心功能的开发了。

构建食物数据模型

要创建食物数据模型来统一存储和管理食物的数据。食物的信息包括:食物名称、卡路里、蛋白质、脂肪、碳水和维生素C等。

在ets目录下新建model文件夹,用于存放数据模型文件。

在model目录下创建DataModels.ets,用于存放数据模型。

定义食物数据的存储模型FoodInfo和枚举变量CategoryId,FoodData类包含食物id、名称(name)、分类(category)、图片(image)、热量(calories)、蛋白质(protein)、脂肪(fat)、碳水(carbohydrates)和维生素C(vitaminC)属性等等。

export enum CategoryId {
  Fruit = 0,
  Vegetable,
  Nut,
  Seafood,
  Dessert
}


export type FoodInfo = {
  id: number
  letter: string
  name: string | Resource
  image: Resource
  categoryId: CategoryId
  calories: number
  protein: number
  fat: number
  carbohydrates: number
  vitaminC: number
}
复制

创建食物资源数据。在ets目录下创建mock文件夹,并在mock文件夹下创建MockData.ets。在MockData.ets中声明食物成分数组代码如下:

import { FoodInfo, CategoryId} from '../model/DataModels'

// 构造数据的mock数据
export let mockFoods: Array<FoodInfo> = [
  {
    id: 0,
    letter: 'Kiwi',
    name: $r('app.string.food_name_kiwi'),
    image: $r('app.media.kiwi'),
    categoryId: CategoryId.Fruit,
    calories: 61,
    protein: 0.8,
    fat: 0.6,
    carbohydrates: 14.5,
    vitaminC: 62
  },
  {
    id: 1,
    letter: 'Walnut',
    name: $r('app.string.food_name_walnut'),
    image: $r('app.media.walnut'),
    categoryId: CategoryId.Nut,
    calories: 646,
    protein: 14.9,
    fat: 58.8,
    carbohydrates: 19.1,
    vitaminC: 1.0
  },
  {
    id: 2,
    letter: 'Cucumber',
    name: $r('app.string.food_name_cucumber'),
    image: $r('app.media.cucumber'),
    categoryId: CategoryId.Vegetable,
    calories: 16,
    protein: 0.8,
    fat: 0.2,
    carbohydrates: 2.9,
    vitaminC: 9.0
  },
  {
    id: 3,
    letter: 'Blueberry',
    name: $r('app.string.food_name_blueberry'),
    image: $r('app.media.blueberry'),
    categoryId: CategoryId.Fruit,
    calories: 57,
    protein: 0.7,
    fat: 0.3,
    carbohydrates: 14.5,
    vitaminC: 9.7
  },
  {
    id: 4,
    letter: 'Crab',
    name: $r('app.string.food_name_crab'),
    image: $r('app.media.crab'),
    categoryId: CategoryId.Seafood,
    calories: 97,
    protein: 19,
    fat: 1.5,
    carbohydrates: 0,
    vitaminC: 7.6
  },
  {
    id: 5,
    letter: 'IceCream',
    name: $r('app.string.food_name_ice_cream'),
    image: $r('app.media.icecream'),
    categoryId: CategoryId.Dessert,
    calories: 150,
    protein: 3.5,
    fat: 11,
    carbohydrates: 24,
    vitaminC: 0.6
  },
  {
    id: 6,
    letter: 'Onion',
    name: $r('app.string.food_name_onion'),
    image: $r('app.media.onion'),
    categoryId: CategoryId.Vegetable,
    calories: 40,
    protein: 1.1,
    fat: 0.2,
    carbohydrates: 9,
    vitaminC: 8.0
  },
  {
    id: 7,
    letter: 'Mushroom',
    name: $r('app.string.food_name_mushroom'),
    image: $r('app.media.mushroom'),
    categoryId: CategoryId.Vegetable,
    calories: 20,
    protein: 3.1,
    fat: 0.3,
    carbohydrates: 3.3,
    vitaminC: 206
  },
  {
    id: 8,
    letter: 'Tomato',
    name: $r('app.string.food_name_tomato'),
    image: $r('app.media.tomato'),
    categoryId: CategoryId.Vegetable,
    calories: 15,
    protein: 0.9,
    fat: 0.2,
    carbohydrates: 3.3,
    vitaminC: 14.0
  },
  {
    id: 9,
    letter: 'Pitaya',
    name: $r('app.string.food_name_pitaya'),
    image: $r('app.media.pitaya'),
    categoryId: CategoryId.Fruit,
    calories: 55,
    protein: 1.1,
    fat: 0.2,
    carbohydrates: 13.3,
    vitaminC: 3.0
  },
  {
    id: 10,
    letter: 'Avocado',
    name: $r('app.string.food_name_avocado'),
    image: $r('app.media.avocado'),
    categoryId: CategoryId.Fruit,
    calories: 171,
    protein: 2.0,
    fat: 15.3,
    carbohydrates: 7.4,
    vitaminC: 8.0
  },
  {
    id: 11,
    letter: 'Strawberry',
    name: $r('app.string.food_name_strawberry'),
    image: $r('app.media.strawberry'),
    categoryId: CategoryId.Fruit,
    calories: 32,
    protein: 1.0,
    fat: 0.2,
    carbohydrates: 7.1,
    vitaminC: 47.0
  }
]
复制

name需要考虑国际化,因此,该值是存储在string.json文件中。

image所引用的食物图片资源,放置在resources >base> media目录下。

在model目录下创建DataUtil.ets,用于加载健康饮食应用的数据。

import { FoodInfo } from './DataModels'
import { mockFoods } from '../mock/MockData'

export function getFoods(): Array<FoodInfo> {
  return mockFoods
}
复制

已完成好健康饮食应用的数据资源准备,接下来将通过加载这些数据来创建食物列表页面。

构建食物列表List布局

使用List组件和ForEach循环渲染,构建食物列表布局。

修改pages目录下的Index.ets文件,新建FoodList组件作为页面入口组件,FoodListItem为其子组件。List组件是列表组件,适用于重复同类数据的展示,其子组件为ListItem,适用于展示列表中的单元。

import { FoodInfo } from '../model/DataModels'
import { getFoods } from '../model/DataUtil'

@Component
struct FoodListItem {
  private foodItem: FoodInfo

  build() {
    Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
      Image(this.foodItem.image)
        .objectFit(ImageFit.Contain)
        .height(40)
        .width(40)
        .margin({ right: 16 })
      Text(this.foodItem.name)
        .fontSize(14)
        .flexGrow(1)
      Text(this.foodItem.calories + ' kcal')
        .fontSize(14)
    }
    .height(64)
    .margin({ right: 24, left: 32 })
  }
}

@Entry
@Component
struct FoodList {
  private foodItems: FoodInfo[] = getFoods()

  build() {
    Column() {
      Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
        Text('Food List')
          .fontSize(20)
          .margin({ left: 20 })
      }
      .height('7%')
      .backgroundColor('#FFf1f3f5')

      List() {
        ForEach(this.foodItems, item => {
          ListItem() {
            FoodListItem({ foodItem: item })
          }
        }, item => item.id.toString())
      }
      .height('93%')
    }
  }
}
复制

运行应用,可以看到列表的效果如下。

构建食物详情页面

在pages目录下,创建FoodDetail.ets文件,FoodDetail页面的食物信息都是直接声明的常量,现在要用传递来的FoodData数据来对其进行重新赋值。整体的FoodDetail.ets代码如下。

import router from '@ohos.router'
import { FoodInfo } from '../model/DataModels'

@Component
struct PageTitle {
  build() {
    Flex({ alignItems: ItemAlign.Start }) {
      Image($r('app.media.back'))
        .width(21.8)
        .height(19.6)
      Text('Food Detail')
        .fontSize(21.8)
        .margin({left: 17.4})
    }
    .height(61)
    .backgroundColor('#FFedf2f5')
    .padding({ top: 13, bottom: 15, left: 28.3 })
    .onClick(() => {
      router.back()
    })
  }
}

@Component
struct FoodImageDisplay {
  private foodItem: FoodInfo
  build() {
    Stack({ alignContent: Alignment.BottomStart }) {
      Image(this.foodItem.image)
        .objectFit(ImageFit.Contain)
      Text(this.foodItem.name)
        .fontSize(26)
        .fontWeight(500)
        .margin({ left: 26, bottom: 17.4 })
    }
    .height(357)
    .backgroundColor('#FFedf2f5')
  }
}

@Component
struct ContentTable {
  private foodItem: FoodInfo

  @Builder IngredientItem(title:string, name: string, value: string) {
    Flex() {
      Text(title)
        .fontSize(17.4)
        .fontWeight(FontWeight.Bold)
        .layoutWeight(1)
      Flex() {
        Text(name)
          .fontSize(17.4)
          .flexGrow(1)
        Text(value)
          .fontSize(17.4)
      }
      .layoutWeight(2)
    }
  }

  build() {
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Start }) {
      this.IngredientItem('Calories', 'Calories', this.foodItem.calories + 'kcal')
      this.IngredientItem('Nutrition', 'Protein', this.foodItem.protein + 'g')
      this.IngredientItem('', 'Fat', this.foodItem.fat + 'g')
      this.IngredientItem('', 'Carbohydrates', this.foodItem.carbohydrates + 'g')
      this.IngredientItem('', 'VitaminC', this.foodItem.vitaminC + 'mg')
    }
    .height(280)
    .padding({ top: 30, right: 30, left: 30 })
  }
}

@Entry
@Component
struct FoodDetail {
  private foodItem: FoodInfo = router.getParams()[foodInfo]

  build() {
    Column() {
      Stack( { alignContent: Alignment.TopStart }) {
        FoodImageDisplay({ foodItem: this.foodItem })
        PageTitle()
      }
      ContentTable({ foodItem: this.foodItem })
    }
    .alignItems(HorizontalAlign.Center)
  }
}
复制

上述代码引用了路由Router API的接口,通过在页面上引入router,可以调用router的各种接口,从而实现页面路由的各种操作。调用router.getParams()[foodInfo]来获取到列表页面跳转来时携带的foodData对应的数据。

列表与详情页面的跳转

上述详情页面已经引用了路由Router API,能否接受来自路由的参数。那么相应的,列表页面也需要做相应的调整,来触发路由跳转。点击Index后跳转到FoodDetail页面。在FoodListItem内创建Navigator组件,使其子组件都具有路由功能,目标页面target为'pages/FoodDetail'。

修改Index.ets文件,

@Component
struct FoodListItem {
  private foodItem: FoodInfo

  build() {
    // 增加路由导航
    Navigator({ target: 'pages/FoodDetail' }) {
      Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
        Image(this.foodItem.image)
          .objectFit(ImageFit.Contain)
          .height(40)
          .width(40)
          .backgroundColor('#FFf1f3f5')
          .margin({ right: 16 })
        Text(this.foodItem.name)
          .fontSize(14)
          .flexGrow(1)
        Text(this.foodItem.calories + ' kcal')
          .fontSize(14)
      }
      .height(64)
    }
    // 页面间数据传递
    .params({ foodInfo: this.foodItem })
    .margin({ right: 24, left:32 })
  }
}
复制

其中,Navigator为路由容器组件,包装了页面路由的能力,指定页面target后,使其包裹的子组件都具有路由能力。.params方法用于页面间数据传递。

程序运行效果

完整演示视频见B站:【老卫搬砖】027期:用HarmonyOS ArkUI来开发一个健康饮食应用_哔哩哔哩_bilibili

源码

见 GitHub - waylau/harmonyos-tutorial: HarmonyOS Tutorial. 《跟老卫学HarmonyOS》 中的“ArkUIHealthyDiet”

相关问题

问题1:路由失效

报错如下:

[manifest_router.cpp(GetPagePath)-(0)] [Engine Log] can't find this page pages/FoodDetail path

解决方案:

main_pages中添加pages/FoodDetail

参考引用

  1. 《跟老卫学HarmonyOS开发》 开源免费教程,GitHub - waylau/harmonyos-tutorial: HarmonyOS Tutorial. 《跟老卫学HarmonyOS》 ↑

  2. 玩转HarmonyOS 3必装DevEco Studio 3,注意避弹 华为开发者论坛

  3. 《鸿蒙 HarmonyOS 应用开发从入门到精通战》(柳伟卫著,北京大学出版社)双十二满100减50

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/77623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构初阶】八大排序算法+时空复杂度

学会控制自己是人生的必修课 文章目录一、插入排序1.直接插入排序2.希尔排序二、选择排序1.直接选择排序2.堆排序&#xff08;已经建好堆的基础之上&#xff09;三、交换排序&#xff08;Swap&#xff09;1.冒泡排序&#xff08;大学牲最熟悉的排序&#xff09;2.快速排序&…

Python 数据库开发实战-Mac系统下通过homebrew安装Redis数据库

此文章的前置条件是 “Mac系统已安装过Homebrew”&#xff0c;如果未安装&#xff0c;可访问 “Mac 安装 homebrew 详细教程” 一文&#xff0c;详细介绍Homebrew的用法。利用 “Homebrew” 对 “Redis” 进行安装管理&#xff0c;那是一个方便啊。 利用 homebrew 安装 Redis …

【Windows逆向】【Qt】日志信息打印

▒ 目录 ▒&#x1f6eb; 导读需求开发环境1️⃣ 示例程序Demo2️⃣ 编写功能&#xff08;QtCreator版本&#xff09;3️⃣ 编写功能&#xff08;VS版本&#xff09;&#x1f6ec; 文章小结&#x1f4d6; 参考资料&#x1f6eb; 导读 需求 调试是编程中常见的定位手段&#xf…

字节一面,操作系统这题没答好,可惜了

问题引入&#xff1a; 在曾经我们学习Linux的经历中&#xff0c;我们也是多次使用信号的。比如&#xff1a;当我们在使用xshell时&#xff0c;在命令行中按Ctrlc&#xff0c;这个键盘输入产生了一个硬件中断&#xff0c;被操作系统获取&#xff0c;解释成信号&#xff0c;发送…

两百行C++代码实现yolov5车辆计数部署(通俗易懂版)

这周用opencv简单实现了一下基于yolov5检测器的车辆计数功能&#xff0c;方法是撞线计数&#xff0c;代码很简单一共就两百多行&#xff0c;测试视频是在b站随便下载的。注&#xff1a;该代码只能演示视频demo效果&#xff0c;一些功能未完善&#xff0c;离实际工程应用还有距离…

JMeter整体综述

JMeter整体综述1. JMeter体系结构及运行原理1.1 主要的组件1.2 运行原理2. 元件执行顺序和作用域2.1 元件执行顺序2.2 元件执行作用域3. 参考1. JMeter体系结构及运行原理 负载模拟&#xff1a;负责模拟用户请求。如取样器有参数化的需求&#xff0c;可通过配置元件或前置处理器…

15.JavaScript 01

文章目录一、概念二、功能三、 JavaScript发展史四、 ECMAScript&#xff1a;客户端脚本语言的标准1、基本语法1. 与html结合方式2. 注释3. 数据类型4. 变量5. 运算符6. 流程控制语句7. JS特殊语法8. 练习&#xff1a;99乘法表2、基本对象1. Function&#xff1a;函数(方法)对象…

上线3天,下载4万,ChatGPT 中文版VSCode插件来了

ChatGPT 的 Debug 功能&#xff0c;有人应用化了。 ChatGPT 这几天可谓是风头无两。作为一个问答语言模型&#xff0c;它最大的优点就是可以回答与编程相关的问题&#xff0c;甚至回复一段代码。 尽管有人指出 ChatGPT 生成的代码有错误&#xff0c;但程序员们还是对它写代码、…

图像配准开源数据集资源汇总

Brown 数据集 数据集下载链接&#xff1a;http://suo.nz/3042bh 数据集由 1024 x 1024 位图 (.bmp) 图像组成&#xff0c;每个图像包含一个 16 x 16 图像块阵列。每个补丁都被采样为 64 x 64 灰度&#xff0c;具有规范的比例和方向。 ETHZ Toys 数据集下载链接&#xff1a…

Java中的语法糖(真甜)

什么是语法糖&#xff08;Syntactic sugar&#xff09; 语法糖是一个计算机数据&#xff0c;特指在编程语言中添加的某种语法&#xff0c;这种语法对语言的功能没有影响&#xff0c;但是更方便程序员使用。语法糖让程序更加简洁&#xff0c;有更高的可读性。 糖嘛&#xff0c…

08.DashBoard流监控配置

08.DashBoard流监控配置 每个服务提供者都需要实现actuator&#xff0c;才可以实现流量监控。 导入Maven依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><…

【图像去噪】空域+频域滤波图像去噪【含GUI Matlab源码 914期】

⛄一、获取代码方式 获取代码方式1&#xff1a; 完整代码已上传我的资源&#xff1a;【图像去噪】基于matlab GUI空域频域滤波图像去噪【含Matlab源码 914期】 获取代码方式2&#xff1a; 通过订阅紫极神光博客付费专栏&#xff0c;凭支付凭证&#xff0c;私信博主&#xff0…

移动端防抓包实践

目录介绍 01.整体概述介绍 1.1 项目背景1.2 思考问题1.3 设计目标1.4 收益分析 02.市面抓包的分析 2.1 Https三要素2.2 抓包核心原理2.3 搞定CA证书2.4 突破CA证书校验2.5 如何搞定加解密2.6 Charles原理2.7 抓包原理图2.8 抓包核心流程 03.防止抓包思路 3.1 先看如何抓包3.2 …

C++计算机视觉库OpenCV在Visual Studio 2022的配置方法

本文介绍在Visual Studio 2022中配置、编译C 计算机视觉库OpenCV的方法。 1 OpenCV库配置 首先&#xff0c;我们进行OpenCV库的下载与安装。作为一个开源的库&#xff0c;我们直接在其官方下载网站&#xff08;https://opencv.org/releases/&#xff09;中进行下载即可&#x…

实现无入侵式C++代码mock工具

为了实现真正无侵入式的mock&#xff0c;我们基于开源Hook框架Frida-gum提供的API&#xff0c;利用C模板进行封装&#xff0c;作者编写了一个简单实用的mock工具&#xff0c;在此开源分享&#xff08;代码详见附录&#xff09;。背景在单元测试中&#xff0c;往往需要减少被测函…

如何实现高性能网络编程-ChatGPT怎么看

hi ,大家好&#xff0c;我是大师兄。听说最近chatgpt特别火&#xff0c;那我们邀请一下chatgpt如何实现&#xff1a;我们先来小试牛刀&#xff1a;刚开始用先用英文交流一下&#xff0c;然后试一下中文&#xff1a;元芳你怎么看&#xff1f;下期直播主题--网络编程 (如何实现高…

用 AWTK 和 AWPLC 快速开发嵌入式应用程序 (7)- 用状态机实现红绿灯

AWPLC 目前还处于开发阶段的早期&#xff0c;写这个系列文章的目的&#xff0c;除了用来验证目前所做的工作外&#xff0c;还希望得到大家的指点和反馈。如果您有任何疑问和建议&#xff0c;请在评论区留言。 1. 背景 AWTK 全称 Toolkit AnyWhere&#xff0c;是 ZLG 开发的开源…

kaggle实战:基于超市消费数据的用户个性化分析案例

大家好&#xff0c;今天给大家分享一篇 kaggle 数据集的新文章&#xff1a;基于一份超市消费数据集的用户个性化分析以及用户分群的实现。 更多详细内容参考原数据集地址&#xff1a; https://www.kaggle.com/code/sonalisingh1411/customer-personality-analysis-segmentati…

实验八 网络优化与正则化(3)不同优化算法比较

目录7.3 不同优化算法的比较分析7.3.1 优化算法的实验设定7.3.1.1 2D可视化实验7.3.1.2 简单拟合实验7.3.1.3 与Torch API对比&#xff0c;验证正确性7.3.2 学习率调整7.3.2.1 AdaGrad算法7.3.2.2 RMSprop算法7.3.3 梯度估计修正7.3.3.1 动量法7.3.3.2 Adam算法7.3.4 不同优化器…

java基于Springboot的简历系统-计算机毕业设计

项目介绍 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;简历系统当然也不能排除在外。简历系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;…