📱 鸿蒙原生应用实战(一):项目初始化与首页仪表盘开发
系列目录
- 第1篇:项目初始化与首页开发 ←当前
- 第2篇:训练详情页与计时器功能
- 第3篇:历史记录与日历热力图
- 第4篇:身体数据记录与趋势分析
- 第5篇:设置页面与项目总结
一、前言
最近在折腾鸿蒙原生应用开发,想着做一个真正能用起来的 App,于是决定开发一款「健身助手」——一个包含训练计划、计时器、历史记录、身体数据追踪的完整应用。
本篇是系列的第一篇,我们从零开始,完成项目初始化、页面路由配置以及首页仪表盘的开发。
二、开发环境
- IDE:DevEco Studio 5.x
- SDK:HarmonyOS API 23(对应 HarmonyOS 6.0)
- 语言:ArkTS(鸿蒙原生声明式 UI 语言)
- 构建工具:Hvigor(鸿蒙自研构建系统)
- 目标设备:Phone
三、创建项目
打开 DevEco Studio,选择File → New → Create Project。
3.1 选择模板
选择Empty Ability模板,这是最基础的 stage 模式应用模板,后续的所有代码我们都手写,不依赖模板生成的复杂样板。
3.2 配置项目信息
- Project Name:
MyApplication - Bundle Name:
com.example.myapplication - Save Location:自定义路径
- Compatible SDK:API 23
- Device Type:Phone
创建完成后,DevEco Studio 会自动进行 sync,等待右下角提示 sync 完成即可。
3.3 项目结构概览
创建完成后的项目结构如下:
MyApplication/ ├── AppScope/ # 应用级配置 │ ├── app.json5 # 应用信息(bundleName、版本号等) │ └── resources/ # 应用级资源 ├── entry/ # 模块目录 │ ├── src/main/ │ │ ├── ets/ │ │ │ ├── entryability/ # Ability 生命周期 │ │ │ └── pages/ # 页面文件(核心) │ │ ├── module.json5 # 模块配置 │ │ └── resources/ # 模块级资源 │ └── build-profile.json5 # 模块构建配置 ├── build-profile.json5 # 项目级构建配置 └── oh-package.json5 # 包管理四、理解 stage 模式与页面路由
4.1 Stage 模型
鸿蒙应用采用stage 模型(对应 Android 的 Activity 模式),每个应用有一个或多个 Ability。我们使用默认的EntryAbility作为主入口。
在entryability/EntryAbility.ets中,关键方法是onWindowStageCreate,在这里指定首页页面:
onWindowStageCreate(windowStage:window.WindowStage):void{windowStage.loadContent('pages/Index',(err)=>{if(err.code){hilog.error(0x0000,'testTag','Failed to load the content.');return;}});}4.2 页面路由配置
鸿蒙的页面路由需要两步配置:
第一步:在resources/base/profile/main_pages.json中注册所有页面:
{"src":["pages/Index","pages/WorkoutPage","pages/HistoryPage","pages/BodyDataPage","pages/SettingsPage"]}⚠️注意:每新增一个页面,都需要在这里注册,否则会报路由找不到的错误。
第二步:在代码中使用router.pushUrl()跳转页面:
importrouterfrom'@ohos.router';// 跳转到训练详情页router.pushUrl({url:'pages/WorkoutPage'});// 返回上一页router.back();五、首页仪表盘开发
首页是用户打开 App 后看到的第一个页面,我把它设计成一个信息概览型的仪表盘。
5.1 页面布局设计
首页包含以下几个区域:
- 顶部标题栏— 显示 App 名称 + 当前日期
- 今日概览卡片— 消耗卡路里 + 完成进度
- 进度条— 可视化今日训练完成度
- 今日训练列表— 显示今日待完成动作
- 开始训练按钮— 跳转到训练详情页
- 快捷入口— 历史记录、身体数据、设置
5.2 核心代码分析
5.2.1 数据处理
我们使用@State装饰器定义响应式数据:
@StatecurrentDate:string='';@StatetodayWorkouts:WorkoutItem[]=[];@StatetodayCalories:number=0;@StatecompletedCount:number=0;@StatetotalCount:number=0;@State是 ArkTS 中最常用的装饰器,被它修饰的变量发生变化时,会自动触发 UI 重新渲染。
5.2.2 训练数据模型
我们定义一个WorkoutItem接口来描述一个训练动作:
interfaceWorkoutItem{id:string;name:string;target:string;// 目标肌群sets:number;// 组数reps:number;// 次数icon:string;// 表情图标completed:boolean;unit?:string;// 单位(可选,如"分钟")}5.2.3 今日训练数据
用模拟数据初始化今日训练计划:
loadTodayWorkouts():void{this.todayWorkouts=[{id:'1',name:'俯卧撑',target:'胸部 · 三头肌',sets:4,reps:15,icon:'💪',completed:false},{id:'2',name:'深蹲',target:'腿部 · 臀部',sets:4,reps:20,icon:'🦵',completed:false},{id:'3',name:'引体向上',target:'背部 · 二头肌',sets:3,reps:8,icon:'🏋️',completed:false},{id:'4',name:'平板支撑',target:'核心肌群',sets:3,reps:1,icon:'🧘',completed:false,unit:'分钟'},];this.totalCount=this.todayWorkouts.length;}5.2.4 构建 UI
ArkTS 使用声明式语法构建 UI,核心是build()方法:
build(){Column(){// 顶部标题栏Column(){Text('健身助手').fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')Text(this.currentDate).fontSize(14).fontColor('rgba(255,255,255,0.8)').margin({top:4})}.width('100%').padding({top:48,bottom:20}).backgroundColor('#FF6B35')Scroll(){Column(){// ... 页面内容}}}}这里有几个关键点:
- Column / Row:线性布局容器,类似 Flexbox 的 flex-direction
- Scroll:可滚动容器,内容超出屏幕时自动滚动
- .width(‘100%’) / .layoutWeight(1):灵活的尺寸控制
5.2.5 统计卡片
使用@Builder装饰器封装可复用的 UI 组件:
@BuilderstatCard(icon:string,label:string,value:string,unit:string){Column(){Text(icon).fontSize(28)Text(value).fontSize(28).fontWeight(FontWeight.Bold).fontColor('#FF6B35')Text(unit).fontSize(12).fontColor('#999')Text(label).fontSize(13).fontColor('#666')}.width('45%').padding(16).backgroundColor('#FFFFFF').borderRadius(16).shadow({radius:4,color:'rgba(0,0,0,0.08)'})}调用方式:
this.statCard('🔥','今日消耗',`${this.todayCalories}`,'千卡')this.statCard('✅','完成进度',`${this.completedCount}/${this.totalCount}`,'个动作')5.2.6 复选框勾选完成
每个训练动作右侧有一个Toggle复选框,勾选时更新完成状态:
Toggle({type:ToggleType.Checkbox,isOn:item.completed}).selectedColor('#FF6B35').onChange((isOn:boolean)=>{this.toggleWorkout(index);})勾选后,动名称自动添加删除线,进度条同步更新。
六、遇到的坑与总结
6.1 踩坑记录
坑1:const声明不能在build()方法内使用
一开始我这样写:
build(){if(condition){constitem=this.workoutItems[index];// ❌ 编译报错}}ArkTS 的build()方法内只能包含 UI 声明语法,不能声明局部变量。解决方案是用@Builder抽离:
@BuilderworkoutCard(item:WorkoutItem,index:number){// UI 代码}坑2:progressColor属性不存在
新版 SDK 中,Progress组件的颜色设置从.progressColor()改为了.color()。
6.2 主题色设计
App 采用橙色调作为主题色#FF6B35,营造运动活力的感觉。背景使用浅灰色#F5F5F5,卡片使用白色加阴影,信息层次分明。
七、下篇预告
下一篇我们将开发训练详情页——包括动作展示、计时器(开始/暂停/重置)、组数完成标记,以及训练完成庆祝弹窗。这是整个 App 最核心的功能页面,敬请期待!
下一篇:训练详情页与计时器功能 →