【共创季稿事节】HarmonyOS动态任务列表开发实战

HarmonyOS 动态任务列表应用开发实战

API Version 24 | ArkUI 声明式 UI | ArkTS

一、前言

随着 HarmonyOS Next 的推进,越来越多的开发者关注纯血鸿蒙应用开发。ArkTS 融合了 TypeScript 的类型安全与声明式 UI 的开发效率,为移动端开发带来全新体验。

本文以一个完整的 "动态任务列表" 应用为案例,从项目结构、页面布局、状态管理到交互逻辑,带您掌握 HarmonyOS 应用开发的核心技术。

二、应用功能概览

本应用是一个功能完整的待办事项管理工具,包含以下特性:

  1. 新建任务 --- 输入标题、可选副标题,选择优先级(高/中/低)
  2. 任务列表展示 --- 标题、副标题、优先级彩色标签
  3. 完成状态切换 --- 点击任务项切换,已完成显示删除线和绿色对勾
  4. 左滑删除 --- 向左滑动露出红色删除按钮
  5. 清除已完成 --- 一键清除所有已完成任务
  6. 重置示例 --- 恢复三个预设示例任务
  7. 实时统计 --- 顶部显示任务总数

三、项目结构

使用 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 数据模型层

通过枚举和自定义类定义任务的数据结构:

typescript 复制代码
enum Priority {
  HIGH = 'HIGH', MEDIUM = 'MEDIUM', LOW = 'LOW'
}

class TaskItem {
  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 的核心模式:

typescript 复制代码
@Entry
@Component
struct Index {
  @State tasks: TaskItem[] = [];
  @State newTaskTitle: string = '';
  @State newTaskSubtitle: string = '';
  @State newTaskPriority: Priority = Priority.HIGH;
  @State priorityPickerShow: boolean = false;

  aboutToAppear(): void {
    this.resetSampleTasks();
  }
  // ... 方法
}
装饰器 作用
@Entry 标记为页面入口,可作为路由目标
@Component 声明该结构体是 UI 组件
@State 标记为响应式状态,修改后自动触发 UI 刷新

4.3 顶层布局

采用 Column 纵向布局,背景色为浅灰色(#F2F2F7),模拟分组列表效果:

typescript 复制代码
build() {
  Column() {
    // 1. 标题栏
    // 2. 新建任务输入区
    // 3. 操作按钮
    // 4. 任务列表
    // 5. 底部提示
  }
  .width('100%').height('100%').backgroundColor('#F2F2F7')
}

4.4 标题栏

使用 Row 水平布局,左侧应用名称,右侧任务总数,中间用 Blank() 撑满:

typescript 复制代码
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 双向绑定数据:

typescript 复制代码
TextInput({ placeholder: '输入新任务...', text: this.newTaskTitle })
  .placeholderColor('#C7C7CC').fontSize(16).height(44).padding({ left: 12 })
  .onChange((value: string) => { this.newTaskTitle = value; })

优先级选择器 设计为弹出式下拉菜单,使用 Radio 单选组件:

typescript 复制代码
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 添加任务逻辑

typescript 复制代码
addTask(): void {
  const title = this.newTaskTitle.trim();
  if (!title) return;
  this.tasks.push(
    new TaskItem(title, this.newTaskSubtitle.trim(), this.newTaskPriority, false)
  );
  this.newTaskTitle = '';
  this.newTaskSubtitle = '';
  this.newTaskPriority = Priority.HIGH;
}

由于 tasks@State 装饰,push 操作自动触发列表重新渲染。ArkTS 对数组的响应式追踪支持 pushsplicefilter 等常见操作。

4.7 操作按钮区

两个按钮并排,分别使用红色和绿色背景,内部包含图标 + 文字:

typescript 复制代码
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 组合:

typescript 复制代码
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 --- 遍历数组,增量更新 DOM
  • swipeAction --- 左滑操作,使用 @Builder 构建面板
  • divider --- 列表分隔线,支持缩进控制
  • .layoutWeight(1) --- 占满剩余空间

4.9 左滑删除

swipeActionend 属性接收构建函数。ArkTS 不支持 Function.bind,使用 lambda 闭包 传参:

typescript 复制代码
@Builder deleteSwipeAction(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 条件样式渲染

根据完成状态动态切换样式:

typescript 复制代码
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 核心方法

typescript 复制代码
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 = [
    new TaskItem('学习 @State 装饰器', '掌握声明式响应式数据绑定', Priority.HIGH, true),
    new TaskItem('探索 Grid 布局', '了解网格布局的参数配置', Priority.LOW, false),
    new TaskItem('完成第一篇笔记', '将学到的知识整理成文档', 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 构建

终端执行:

bash 复制代码
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.json5pages 是否指向正确的 $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 组件销毁前,清理资源

八、扩展方向

当前应用功能完整,还可扩展:

  1. 数据持久化 --- 使用 @ohos.data.preferences@ohos.data.relationalStore 保存任务
  2. 任务编辑 --- 长按弹出对话框修改标题/副标题/优先级
  3. 搜索筛选 --- 按关键词搜索、按优先级筛选
  4. 拖拽排序 --- 使用 ListItemdragEnabled 属性
  5. 时间提醒 --- 结合 @ohos.backgroundTaskManager 发送本地通知
  6. 深色模式 --- 监听 configurationChange 切换主题

九、总结

本文从零构建了一个完整的 HarmonyOS 动态任务列表应用,涵盖了:

  1. ArkTS 基础 --- 枚举、类、装饰器、泛型
  2. ArkUI 核心组件 --- Column、Row、Text、TextInput、Button、List、Image、Radio、Stack
  3. 声明式 UI 语法 --- 条件渲染、循环渲染、@Builder
  4. 响应式状态 --- @State 与数组响应式追踪
  5. 事件处理 --- onClick、onChange、swipeAction
  6. 资源管理 --- SVG 图标引用与动态着色
  7. 构建部署 --- Hvigor 流程与问题排查

通过这个项目,您已掌握 HarmonyOS 应用开发的核心流程。声明式 UI 需要一些时间适应,但上手后会发现代码更简洁、维护成本更低。

项目完整代码位于 entry/src/main/ets/pages/Index.ets,SVG 图标位于 resources/base/media/。使用 DevEco Studio 打开即可运行体验。

本文发布于 HarmonyOS Next API 24,所有代码均已通过 hvigorw assembleHap 构建验证,零错误零警告。

相关推荐
祭曦念2 小时前
【共创季稿事节】鸿蒙原生ArkTS动态列表布局实战_State_ForEach完整指南
华为·harmonyos
不羁的木木2 小时前
《HarmonyOS 6.1 新能力实战之智感握姿》第二篇:核心功能——查询与监听握持手状态
华为·harmonyos
风华圆舞3 小时前
鸿蒙 + Flutter 下 AI 页面的状态协同设计
人工智能·flutter·harmonyos
互联网散修3 小时前
鸿蒙实战:仿小红书“我”的页面——从分层架构到沉浸式交互
交互·harmonyos
aqi004 小时前
一文速览 HarmonyOS 6.1.1 推出的十个新特性
android·华为·harmonyos·鸿蒙·harmony
木咺吟4 小时前
鸿蒙原生应用实战(三):游戏详情页与交互功能 — 400行ArkTS深度实践
harmonyos
芒鸽4 小时前
HarmonyOS 数据持久化开发实战:KVStore、关系型数据库与 Preferences
数据库·华为·harmonyos
TrisighT4 小时前
ArkTS 组件传对象还是拆属性?我测了帧率,结果和直觉反着来
harmonyos·arkts
木咺吟4 小时前
鸿蒙原生应用开发实战(四):电影详情与评分评价 — 电影清单App
harmonyos