本文演示如果在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: numberletter: stringname: string | Resourceimage: ResourcecategoryId: CategoryIdcalories: numberprotein: numberfat: numbercarbohydrates: numbervitaminC: 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: FoodInfobuild() {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: FoodInfobuild() {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: FoodInfobuild() {// 增加路由导航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方法用于页面间数据传递。
程序运行效果
相关问题
问题1:路由失效
报错如下:
[manifest_router.cpp(GetPagePath)-(0)] [Engine Log] can’t find this page pages/FoodDetail path
解决方案:
main_pages中添加pages/FoodDetail
最后
随着鸿蒙开发越来越火热,我了解到现在有很多小伙伴想入行鸿蒙,但又不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。我给大家整理了一份实用的鸿蒙(Harmony OS)开发学习手册资料用来跟着学习是非常有利于帮助大家提升鸿蒙开发技术的。
相对于网上那些碎片化的知识内容,这份学习资料的知识点更加系统化,更容易理解和记忆。资料包含了、应用开发导读(ArkTS)、HarmonyOS 概念、如何快速入门、开发基础知识、基于ArkTS 开发、等鸿蒙开发必掌握的核心知识要点,内容包含了(技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
获取这份完整版高清学习路线,请点击→《一小时快速认识HarmonyOS》
鸿蒙(Harmony NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了几套HarmonyOS NEXT学习视频 内容包含以下联
内容包含:ArkTS、ArkUI、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→《鸿蒙星河版开发教程》
D·TS语法教程
领取以上完整高清学习视频,请点击→《鸿蒙 (Harmony OS)D·TS语法教程》小编自己整理的部分学习资料(包含有高清视频、开发文档、电子书籍等)
ArkTS基础链接
领取以上完整高清学习视频,请点击→《鸿蒙HarmonyOS:ArkTS基础链接》小编自己整理的部分学习资料(包含有高清视频、开发文档、电子书籍等)
TypeScript链接
领取以上完整高清学习视频,请点击→《HarmonyOS;TypeScript链接》小编自己整理的部分学习资料(包含有高清视频、开发文档、电子书籍等)