HarmonyOS 动态任务列表应用开发实战
API Version 24 | ArkUI 声明式 UI | ArkTS
一、前言
随着 HarmonyOS Next 的推进,越来越多的开发者关注纯血鸿蒙应用开发。ArkTS 融合了 TypeScript 的类型安全与声明式 UI 的开发效率,为移动端开发带来全新体验。
本文以一个完整的“动态任务列表”应用为案例,从项目结构、页面布局、状态管理到交互逻辑,带您掌握 HarmonyOS 应用开发的核心技术。
二、应用功能概览
本应用是一个功能完整的待办事项管理工具,包含以下特性:
- 新建任务— 输入标题、可选副标题,选择优先级(高/中/低)
- 任务列表展示— 标题、副标题、优先级彩色标签
- 完成状态切换— 点击任务项切换,已完成显示删除线和绿色对勾
- 左滑删除— 向左滑动露出红色删除按钮
- 清除已完成— 一键清除所有已完成任务
- 重置示例— 恢复三个预设示例任务
- 实时统计— 顶部显示任务总数
三、项目结构
使用 DevEco Studio 创建 Empty Ability 模板项目(API 24),目录结构如下:
app6124/ ├── AppScope/app.json5 # 应用级配置 ├── entry/src/main/ │ ├── ets/ │ │ ├── entryability/ # Ability 生命周期 │ │ └── pages/Index.ets # 主页面 │ ├── module.json5 # 模块配置 │ └── resources/base/media/ # 图标资源(SVG) ├── build-profile.json5 # 项目级构建 └── hvigor/ # Hvigor 构建配置四、核心技术实现
4.1 数据模型层
通过枚举和自定义类定义任务的数据结构:
enumPriority{HIGH='HIGH',MEDIUM='MEDIUM',LOW='LOW'}classTaskItem{title:string;subtitle:string;priority:Priority;completed:boolean;constructor(title:string,subtitle:string,priority:Priority,completed:boolean){this.title=title;this.subtitle=subtitle;this.priority=priority;this.completed=completed;}}使用enum+class的组合,配合@State装饰器实现响应式追踪。当任务对象的属性变化时,ArkUI 会自动侦测并刷新 UI。
4.2 主页面结构
页面使用@Entry和@Component装饰器标记,这是 ArkTS 声明式 UI 的核心模式:
@Entry@Componentstruct Index{@Statetasks:TaskItem[]=[];@StatenewTaskTitle:string='';@StatenewTaskSubtitle:string='';@StatenewTaskPriority:Priority=Priority.HIGH;@StatepriorityPickerShow:boolean=false;aboutToAppear():void{this.resetSampleTasks();}// ... 方法}| 装饰器 | 作用 |
|---|---|
@Entry | 标记为页面入口,可作为路由目标 |
@Component | 声明该结构体是 UI 组件 |
@State | 标记为响应式状态,修改后自动触发 UI 刷新 |
4.3 顶层布局
采用Column纵向布局,背景色为浅灰色(#F2F2F7),模拟分组列表效果:
build(){Column(){// 1. 标题栏// 2. 新建任务输入区// 3. 操作按钮// 4. 任务列表// 5. 底部提示}.width('100%').height('100%').backgroundColor('#F2F2F7')}4.4 标题栏
使用Row水平布局,左侧应用名称,右侧任务总数,中间用Blank()撑满:
Row(){Text('动态任务列表').fontSize(22).fontWeight(FontWeight.Bold).fontColor('#1C1C1E')Blank()Text(`共${this.tasks.length}项`).fontSize(14).fontColor('#8E8E93')}.width('100%').padding({left:16,right:16,top:12,bottom:8})Blank组件类似于 Flexbox 的flex-grow: 1,自动占据剩余空间实现两端对齐。
4.5 新建任务输入区
输入区包含三部分:标题输入框、副标题输入框、优先级选择器 + 添加按钮行。
TextInput组件通过@State双向绑定数据:
TextInput({placeholder:'输入新任务...',text:this.newTaskTitle}).placeholderColor('#C7C7CC').fontSize(16).height(44).padding({left:12}).onChange((value:string)=>{this.newTaskTitle=value;})优先级选择器设计为弹出式下拉菜单,使用Radio单选组件:
if(this.priorityPickerShow){Column(){ForEach([Priority.HIGH,Priority.MEDIUM,Priority.LOW],(p:Priority)=>{Row(){Radio({value:this.getPriorityText(p),group:'priority'}).checked(this.newTaskPriority===p).onChange(()=>{this.setPriority(p);})Text(this.getPriorityText(p)).fontSize(15)}.onClick(()=>{this.setPriority(p);})})}// ...样式}这里使用条件渲染(if直接写在 UI 描述中)控制下拉菜单显示隐藏,比visible属性更直观高效。
4.6 添加任务逻辑
addTask():void{consttitle=this.newTaskTitle.trim();if(!title)return;this.tasks.push(newTaskItem(title,this.newTaskSubtitle.trim(),this.newTaskPriority,false));this.newTaskTitle='';this.newTaskSubtitle='';this.newTaskPriority=Priority.HIGH;}由于tasks被@State装饰,push操作自动触发列表重新渲染。ArkTS 对数组的响应式追踪支持push、splice、filter等常见操作。
4.7 操作按钮区
两个按钮并排,分别使用红色和绿色背景,内部包含图标 + 文字:
Button(){Row(){Image($r('app.media.ic_checkmark')).width(16).height(16).fillColor('#FFFFFF')Text('清除已完成').fontSize(14).fontColor('#FFFFFF').margin({left:4})}}.height(36).backgroundColor('#FF3B30').borderRadius(18).padding({left:14,right:14}).onClick(()=>{this.clearCompleted();})使用带子组件的 Button——Button()不传 label,内部用Row+Image+Text自定义内容。这与Button('文字')的单标签模式是两种不同用法。
4.8 任务列表
使用List+ListItem+ForEach组合:
List({space:0}){ForEach(this.tasks,(task:TaskItem,index:number)=>{ListItem(){// 任务卡片 UI}.onClick(()=>{this.toggleTaskCompletion(index);}).swipeAction({end:():void=>this.deleteSwipeAction(index)})})}.width('100%').layoutWeight(1).divider({strokeWidth:'0.5px',color:'#E5E5EA',startMargin:52,endMargin:0})ForEach— 遍历数组,增量更新 DOMswipeAction— 左滑操作,使用@Builder构建面板divider— 列表分隔线,支持缩进控制.layoutWeight(1)— 占满剩余空间
4.9 左滑删除
swipeAction的end属性接收构建函数。ArkTS 不支持Function.bind,使用lambda 闭包传参:
@BuilderdeleteSwipeAction(index:number){Button(){Image($r('app.media.ic_delete')).width(24).height(24).fillColor('#FFFFFF')}.width(68).height('100%').backgroundColor('#FF3B30').borderRadius(0).onClick(()=>{this.deleteTask(index);})}@Builder装饰器可以将一段 UI 描述封装为可复用构建函数,内可直接编写声明式 UI 代码。
4.10 条件样式渲染
根据完成状态动态切换样式:
Image(task.completed?$r('app.media.ic_checkmark_circle'):$r('app.media.ic_circle')).fillColor(task.completed?'#34C759':'#C7C7CC')Text(task.title).fontColor(task.completed?'#8E8E93':'#1C1C1E').decoration({type:task.completed?TextDecorationType.LineThrough:TextDecorationType.None})使用三元运算符动态控制样式属性,无需分支代码,非常简洁。
4.11 核心方法
toggleTaskCompletion(index:number):void{if(index>=0&&index<this.tasks.length){this.tasks[index].completed=!this.tasks[index].completed;}}deleteTask(index:number):void{if(index>=0&&index<this.tasks.length){this.tasks.splice(index,1);}}clearCompleted():void{this.tasks=this.tasks.filter(task=>!task.completed);}resetSampleTasks():void{this.tasks=[newTaskItem('学习 @State 装饰器','掌握声明式响应式数据绑定',Priority.HIGH,true),newTaskItem('探索 Grid 布局','了解网格布局的参数配置',Priority.LOW,false),newTaskItem('完成第一篇笔记','将学到的知识整理成文档',Priority.MEDIUM,false),];}修改@State数组后,UI 自动响应式更新。
五、资源文件管理
在resources/base/media/下存放 6 个 SVG 图标:
| 文件 | 用途 |
|---|---|
ic_arrow_down.svg | 优先级下拉箭头 |
ic_checkmark.svg | 对勾图标 |
ic_checkmark_circle.svg | 实心圆圈对勾(已完成) |
ic_circle.svg | 空心圆圈(未完成) |
ic_refresh.svg | 刷新图标 |
ic_delete.svg | 删除图标 |
SVG 图标的优势是可通过.fillColor()动态修改颜色,无需为每种颜色准备独立图片。
六、构建与部署
6.1 构建
终端执行:
hvigorw assembleHap流程:PreBuild → CreateModuleInfo → MergeProfile → ProcessResource →CompileArkTS→ PackageHap → SignHap → 完成。
6.2 常见问题
问题 1:Button 标签冲突
Error: The Button component with a label parameter can not have any child.要么用Button('文字')不带花括号,要么用Button() { Text('文字') },二者选一。
问题 2:Function.bind 不支持
Error: 'Function.bind' is not supported (arkts-no-func-bind)ArkTS 禁用了bind,改用 lambda:() => this.myMethod(arg)。
问题 3:属性命名冲突
Warning: ... cannot have name as 'activeCount'.某些名称与系统属性冲突,换名即可(如incompleteCount)。
问题 4:运行时闪退
检查module.json5中pages是否指向正确的$profile:main_pages,以及main_pages.json的页面路径是否匹配。
七、ArkTS 开发最佳实践
7.1 声明式 UI 思维
ArkTS 采用声明式范式,与传统命令式 UI 本质不同:
| 传统命令式 | ArkTS 声明式 |
|---|---|
| 手动 findViewById | 直接编写 UI 描述 |
| 手动 setText/setColor | UI 自动随状态变化 |
| 复杂的 Diff 刷新 | 细粒度响应式追踪 |
写作 UI 时思考"当前状态下 UI 应该什么样",而非"怎么修改控件"。
7.2 响应式状态体系
| 装饰器 | 场景 |
|---|---|
@State | 组件内自有状态 |
@Prop | 父→子单向传递 |
@Link | 父子双向同步 |
@Provide/@Consume | 跨层级通信 |
@Observed/@ObjectLink | 深层对象观测 |
7.3 组件化拆分建议
应用功能增长时拆分为子组件:
Index → TaskHeader + TaskInput(含 PriorityPicker) → TaskActions + TaskList(含 TaskCard)+ TaskFooter子组件通过@Prop/@Link通信,保持代码清晰可维护。
7.4 生命周期
| 钩子 | 时机 |
|---|---|
aboutToAppear | 组件创建前,初始化数据 |
onPageShow | 页面显示 |
onPageHide | 页面隐藏 |
aboutToDisappear | 组件销毁前,清理资源 |
八、扩展方向
当前应用功能完整,还可扩展:
- 数据持久化— 使用
@ohos.data.preferences或@ohos.data.relationalStore保存任务 - 任务编辑— 长按弹出对话框修改标题/副标题/优先级
- 搜索筛选— 按关键词搜索、按优先级筛选
- 拖拽排序— 使用
ListItem的dragEnabled属性 - 时间提醒— 结合
@ohos.backgroundTaskManager发送本地通知 - 深色模式— 监听
configurationChange切换主题
九、总结
本文从零构建了一个完整的 HarmonyOS 动态任务列表应用,涵盖了:
- ArkTS 基础— 枚举、类、装饰器、泛型
- ArkUI 核心组件— Column、Row、Text、TextInput、Button、List、Image、Radio、Stack
- 声明式 UI 语法— 条件渲染、循环渲染、@Builder
- 响应式状态— @State 与数组响应式追踪
- 事件处理— onClick、onChange、swipeAction
- 资源管理— SVG 图标引用与动态着色
- 构建部署— Hvigor 流程与问题排查
通过这个项目,您已掌握 HarmonyOS 应用开发的核心流程。声明式 UI 需要一些时间适应,但上手后会发现代码更简洁、维护成本更低。
项目完整代码位于
entry/src/main/ets/pages/Index.ets,SVG 图标位于resources/base/media/。使用 DevEco Studio 打开即可运行体验。本文发布于 HarmonyOS Next API 24,所有代码均已通过
hvigorw assembleHap构建验证,零错误零警告。