ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 HarmonyOS ArkUI 开发健康饮食应用:ArkUIHealthyDiet 列表与详情页实战剖析

用 HarmonyOS ArkUI 开发健康饮食应用:ArkUIHealthyDiet 列表与详情页实战剖析 示例工程【免费下载链接】harmonyos-tutorialHarmonyOS Tutorial. 《跟老卫学HarmonyOS开发》项目地址https://gitcode.com/GitHub_Trending/ha/harmonyos-tutorial点击查看免费下载本文以开源仓库 harmonyos-tutorial 中的 ArkUIHealthyDiet 示例为研究对象完整讲解如何用 HarmonyOS ArkUI声明式 UI eTS/ArkTS从零搭建一个「食物列表 → 食物详情」的健康饮食应用。读完本文你将掌握 List ForEach 列表渲染、Navigator 页面跳转与参数传递、Builder 复用组件、ohos.router 参数回读、$r() 资源引用以及 mock 数据分层等一套可复用的 ArkUI 开发套路可直接迁移到购物、资讯、菜谱等同类列表详情型应用。一、示例定位一个最小可用的「列表 详情」ArkUI 应用ArkUIHealthyDiet 是 harmonyos-tutorial 仓库《跟老卫学HarmonyOS开发》配套示例中基于ArkTSeTS 声明式开发范式编写的健康饮食应用示例。整个工程不依赖任何第三方业务库仅用 ArkUI 核心组件完成了一个完整闭环首页Index.ets以列表形式展示 12 种常见食物猕猴桃、核桃、黄瓜、蓝莓、螃蟹、冰淇淋、洋葱、蘑菇、番茄、火龙果、牛油果、草莓的名称、热量与图标详情页FoodDetail.ets点击列表项跳转后展示对应食物的图片、名称以及 Calories热量、Protein蛋白质、Fat脂肪、Carbohydrates碳水化合物、VitaminC维生素 C五维营养成分表。从工程结构看samples/ArkUIHealthyDiet它遵循标准 Stage 模型工程布局AppScope存放应用级配置entry是唯一的 entry 类型模块entry/src/main/ets下按entryability、mock、model、pages四个职责目录组织代码samples/ArkUIHealthyDiet/ ├── AppScope/app.json5 # 应用级配置bundleName、版本等 ├── entry/ │ ├── src/main/ │ │ ├── ets/ │ │ │ ├── entryability/EntryAbility.ts # 应用入口 Ability │ │ │ ├── mock/MockData.ets # 食物 mock 数据 │ │ │ ├── model/DataModels.ets # 类型与枚举定义 │ │ │ ├── model/DataUtil.ets # 数据获取入口 │ │ │ └── pages/Index.ets # 食物列表页 │ │ │ └── pages/FoodDetail.ets # 食物详情页 │ │ └── module.json5 # 模块级配置 │ └── src/ohosTest/ # 本地单元测试目录 ├── hvigorfile.ts # 构建脚本 └── package.json这种model模型→ mock数据→ pages页面的分层是小型 ArkUI 应用非常实用的组织范式UI 层只依赖数据接口数据层可以随时替换为真实网络请求。二、数据层设计用类型、枚举与 mock 数据支撑 UI2.1 FoodInfo 类型定义核心数据结构定义在 DataModels.ets通过 ArkTS 的export type定义了一个食物信息联合结构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 }几个值得注意的设计点name: string | Resource联合类型既允许直接传字符串也允许传$r(app.string.xxx)生成的 Resource 资源对象兼顾国际化与硬编码两种场景image: Resource图片统一使用资源引用类型配合$r()在编译期完成资源校验categoryId: CategoryId用枚举对食物做分类水果/蔬菜/坚果/海鲜/甜点为后续扩展「按分类筛选」等能力预留了字段营养成分字段统一为number便于详情页直接拼接单位字符串。2.2 Mock 数据12 种食物的完整数据集数据源位于 MockData.etsmockFoods是一个ArrayFoodInfo每条数据都通过$r()引用资源{ 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 },这 12 条数据覆盖了CategoryId中的全部五个分类Fruit、Vegetable、Nut、Seafood、Dessert数据内容为真实可考的营养成分参考值例如核桃Walnut热量 646 kcal、蛋白质 14.9 g、脂肪 58.8 g蘑菇Mushroom维生素 C 高达 206 mg。这种「mock 层 $r 资源引用」的做法意味着页面代码不出现任何硬编码数据图片与文案集中在resources目录管理后续接入真实数据源时只需替换getFoods()的实现。2.3 数据获取入口DataUtil.ets 提供了一个极简的工厂方法import { FoodInfo } from ./DataModels import { mockFoods } from ../mock/MockData export function getFoods(): ArrayFoodInfo { return mockFoods }列表页通过private foodItems: FoodInfo[] getFoods()一次性取数。从源码结构看DataUtil相当于 UI 与 mock 数据之间的门面Facade若将来改为从服务端拉取只需在此函数内部改为异步请求并返回 PromiseUI 层即可无感升级。三、首页实现List ForEach 渲染食物列表首页 Index.ets 由两个组件构成内嵌的FoodListItem负责单个列表项Entry FoodList是页面根组件。3.1 页面骨架标题栏 ListEntry 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%) } } }关键写法拆解页面用Column纵向布局标题区占7%、列表区占93%用百分比高度实现简单的自适应分配ListForEach是 ArkUI 列表页的标准组合第三个参数item item.id.toString()是键值生成器Key Generator用于高效 diff 复用必须以稳定唯一值这里取 id作为键ListItem包裹每个条目FoodListItem({ foodItem: item })以构造参数方式向子组件传值。3.2 列表项Navigator 实现页面跳转并携带参数FoodListItem是整个示例最值得学习的部分——它演示了 ArkUI 最轻量的页面跳转方式NavigatorComponent 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: pages/FoodDetail })声明式路由容器target指向目标页面在main_pages.json中注册的路径如pages/FoodDetail点击其内部区域即触发跳转.params({ foodInfo: this.foodItem })通过params属性把整个FoodInfo对象随路由传递实现页面间数据传递这是 ArkUI 页面传参最直接的方式之一.flexGrow(1)让食物名称占据剩余宽度右侧热量文本自然右对齐图片使用ImageFit.Contain等比缩放保证不同尺寸的食物图标不被拉伸变形。与使用router.pushUrl的编程式跳转相比Navigator的优势在于跳转行为完全由声明式 UI 描述无需在onClick中手写路由代码代码更内聚、更易维护。四、详情页实现Builder 复用与参数回读点击列表项后进入 FoodDetail.ets该页面由PageTitle顶部导航栏、FoodImageDisplay图片与名称展示区、ContentTable营养成分表三个子组件拼装而成是「组件拆分 复用」的典型示范。4.1 用 router.getParams 回读页面参数详情页在组件属性初始化阶段直接读取路由参数import router from ohos.router Entry Component struct FoodDetail { private foodItem: FoodInfo router.getParams()[foodInfo] ... }与列表页用Navigator.params发送参数对应详情页用router.getParams()[foodInfo]接收参数这样Index页跳转时传入的foodItem对象被完整还原详情页即可直接渲染该食物的图片、名称与营养数据注意router来自系统能力模块ohos.router使用前需显式 import。4.2 返回导航栏onClick 触发 router.backPageTitle组件展示了「返回键 标题」的实现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() }) } }返回图标同样通过$r(app.media.back)引用资源整个导航栏注册onClick点击任意位置调用router.back()返回上一页与Navigator的入栈跳转形成完整的路由闭环push/back。4.3 图片展示区Stack 叠加布局FoodImageDisplay用Stack把食物图片与名称文字叠加名称固定于左下角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) } }alignContent: Alignment.BottomStart使子组件按「左下角」对齐是 ArkUI 中实现水印、角标、悬浮文案的通用手法。4.4 营养成分表Builder 抽离可复用 UI 片段ContentTable内部定义了一个Builder修饰的IngredientItem把「左侧标签 右侧名称/数值」的重复行布局抽成可复用片段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 }) } }这段代码集中体现了 ArkUI 的两个布局与复用机制Builder把「标题 名称 数值」三列布局抽象为带参函数this.IngredientItem(Calories, Calories, ...)式调用五行数据共用同一套行样式消除重复代码layoutWeight与flexGrow配合标签列layoutWeight(1)、数值列layoutWeight(2)按 1:2 分配宽度flexGrow(1)让名称自适应伸缩构成典型的「两端对齐表格行」外层Flex纵向排列、justifyContent: FlexAlign.SpaceBetween五行营养数据在 280 高度内均匀分布。五、资源引用与页面注册让 $r() 和路由配置闭环5.1 $r() 资源引用体系示例中所有文案与图片均通过$r()引用例如$r(app.string.food_name_kiwi)引用resources/base/element/string.json中的字符串资源$r(app.media.kiwi)引用resources/base/media/下的图片资源$r(app.media.back)引用返回键图标。$r()的优势在于编译期资源校验资源缺失、拼写错误都会在构建阶段直接暴露且天然支持多语言/多设备资源限定词如resources/zh_CN、resources/en_US目录是 ArkUI 推荐的标准资源引用方式。5.2 路由页面注册Navigator的target: pages/FoodDetail之所以能解析前提是两个页面都已在路由表main_pages.json由 module.json5 中pages: $profile:main_pages指定中注册。从仓库源码看Index 与 FoodDetail 均按pages/页面名的格式登记EntryAbility在 onWindowStageCreate 中通过windowStage.loadContent(pages/Index, ...)指定首页。若新增页面忘记注册Navigator跳转会因找不到路由而失败——这是初学者最容易踩的坑。5.3 模块与应用级配置模块级 module.json5 声明了deviceTypes: [phone]仅支持手机形态、入口 AbilityEntryAbility及其skillsentity.system.homeaction.system.home即桌面启动图标应用级 app.json5 定义了bundleName: com.waylau.hmos.myapplication、versionCode: 1000000、versionName: 1.0.0等打包元数据。两者的label、icon同样使用$string:/$media:资源引用与应用内资源体系保持一致。六、工程化与测试hvigor 构建与 ohosTest 用例6.1 构建工程该示例基于 HarmonyOS 的hvigor构建体系工程根与模块各有一个 hvigorfile.ts模块级 package.json 声明buildTool: hvigor、directoryLevel: module。在 DevEco Studio 中打开工程根目录即可自动完成同步与构建命令行下通过hvigorw assembleHap一类任务产出 HAP 包再部署到真机或模拟器运行deviceTypes限定为 phone。6.2 单元测试骨架工程内置了ohosTest测试模块entry/src/ohosTest包含List.test.ets测试套件入口聚合Ability.testAbility.test.etsAbility 生命周期相关的用例TestAbility.ets/OpenHarmonyTestRunner.ts测试专用 Ability 与测试运行器说明该示例预留了完整的本地测试执行链路可在 DevEco Studio 中直接运行 ohosTest 用例。对本文主题而言可在该测试骨架中为getFoods()补充断言如返回 12 条数据、字段完整性校验验证数据层在后续迭代中不被破坏。七、运行与效果验证使用 DevEco Studio 打开仓库中的 samples/ArkUIHealthyDiet 目录等待 hvigor 依赖同步完成连接 API 版本兼容的 HarmonyOS 手机或启动模拟器点击 Run 运行entry模块首页即展示「Food List」列表点击任意食物条目经Navigator跳转到详情页查看该食物的图片与五维营养表点击左上角返回区域router.back()回到列表验证 push/back 路由闭环。八、小结从本示例可复用的 ArkUI 模式ArkUIHealthyDiet 虽小却浓缩了 ArkUI 声明式开发中最高频的六类模式可直接复用到任意「列表 详情」型应用关注点本示例中的实现复用场景列表渲染ListForEachListItemid 作键商品列表、资讯流、联系人页面跳转Navigatortarget.params()列表到详情的导航参数回读router.getParams()[foodInfo]详情页数据还原返回导航onClickrouter.back()统一返回栏复用 UIBuilder带参函数重复行/卡片布局数据分层DataModelsMockDataDataUtil数据源可替换架构相关源码均可在仓库中继续深读Index.ets、FoodDetail.ets、MockData.ets、DataModels.ets。赞分享示例工程【免费下载链接】harmonyos-tutorialHarmonyOS Tutorial. 《跟老卫学HarmonyOS开发》项目地址https://gitcode.com/GitHub_Trending/ha/harmonyos-tutorial点击查看免费下载相关推荐Gradio与饮食营养健康饮食应用Gradio与饮食营养健康饮食应用 引言当机器学习遇见健康生活 在当今快节奏的生活中保持健康的饮食习惯变得越来越具有挑战性。你是否曾经 想要计算一顿饭的前端后端AI 应用cann/cannbot-skills: easyasc DSL转AscendC工作流ops easyasc dsl Chinese README / 中文版说明 https://link.gitcode.com/i/2096949a8b1a88AI 技能人工智能AI 评测CANNAscendxcit_small_12_p8_224.fb_in1k模型部署指南从本地运行到生产环境xcit_small_12_p8_224.fb_in1k模型部署指南从本地运行到生产环境 想要快速部署高效的图像分类模型吗xcit_small_12_p8_上一篇Sunshine 10 分钟跑通游戏串流上手指南下一篇3分钟解锁微信网页版终极免费插件使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表