鸿蒙新特性:Progress 进度条组件——构建下载管理器与实时进度模拟
文件下载、任务执行、数据加载——几乎所有需要等待的场景都需要进度指示。用户盯着一个静态的"加载中"文字时,每一秒都漫长;但如果看到一个从 0 到 100% 的进度条在平滑推进,等待的焦虑感会大幅降低。进度条不仅是一个视觉元素,更是一个心理工具——它告诉用户"系统在工作,结果即将到来"。
HarmonyOS NEXT ArkUI 提供了 Progress 组件——一个支持五种样式和高度定制的进度指示器。本文将深入讲解 Progress 组件的完整 API,并构建一个"下载管理器"——支持多任务并发下载、实时进度模拟、暂停/继续操作和已完成清理。
关键词:HarmonyOS、ArkUI、Progress、进度条、下载管理、实时模拟、setInterval
一、Progress 组件 API
1.1 基本用法
Progress({ value: this.progress, total: 100, type: ProgressType.Linear })
.width('100%')
.height(6)
.color('#1677FF')
.backgroundColor('#F2F3F5')
核心参数与属性:
| 参数/属性 | 类型 | 说明 |
|---|---|---|
value |
number | 当前进度值 |
total |
number | 总进度值(默认 100) |
type |
ProgressType | 进度条样式 |
.color() |
ResourceColor | 进度填充颜色 |
.backgroundColor() |
ResourceColor | 轨道背景颜色 |
.width() |
Length | 进度条宽度 |
.height() |
Length | 进度条高度(线性时指粗细) |
1.2 五种样式
Progress 组件支持五种样式,通过 ProgressType 枚举选择:
| 样式 | ProgressType | 说明 | 适用场景 |
|---|---|---|---|
| 线性 | Linear |
水平进度条 | 文件下载、任务进度 |
| 环形 | Ring |
圆环进度,从上端顺时针填充 | 加载等待、刷新 |
| 刻度环形 | ScaleRing |
带刻度标记的环形 | 存储空间、电量 |
| 月食 | Eclipse |
月牙形渐变填充 | 上传进度、数据同步 |
| 胶囊 | Capsule |
胶囊形状,可附加文本 | 评分、完成度 |
本文 Demo 使用 Linear 样式——下载管理器中最直观的选择,每个任务一条独立的水平进度条。
1.3 动态更新 value
Progress 本身是静态的——它只渲染 value 参数的当前值。要让进度"动起来",需要通过定时器不断更新 value:
private timerId: number = -1;
startSimulation(): void {
if (this.timerId !== -1) return;
this.timerId = setInterval(() => {
this.tasks = this.tasks.slice().map((task: DownloadTask) => {
if (task.status === 'downloading' && task.progress < 100) {
let inc = Math.floor(Math.random() * 6) + 3; // 增量 3~8
let np = task.progress + inc;
if (np >= 100) return task.withComplete();
return task.withProgress(np);
}
return task;
});
}, 400);
}
每 400 毫秒,所有"下载中"的任务进度增加一个随机值(3~8)。当进度达到或超过 100 时,任务自动标记为完成。随机增量模拟了真实网络下载的速度波动——有些时刻快,有些时刻慢,避免"匀速推进"的机械感。
1.4 定时器的生命周期管理
定时器在 aboutToAppear 中启动,在 aboutToDisappear 中销毁:
aboutToAppear(): void {
this.startSimulation();
}
aboutToDisappear(): void {
this.stopSimulation();
}
stopSimulation(): void {
if (this.timerId !== -1) {
clearInterval(this.timerId);
this.timerId = -1;
}
}
如果不在页面销毁时清除定时器,它会继续在后台运行并尝试更新已销毁组件的状态——这可能导致内存泄漏或运行时错误。timerId 是一个普通类字段(非 @State),因为它只用于定时器控制,不参与 UI 渲染。
二、下载管理器的整体设计
2.1 页面架构
DownloadPage
├── 标题栏 — "下载管理" + 进行中计数
├── 添加下载区域 — 说明文字 + "+ 添加"按钮
├── 下载任务列表(Scroll)
│ ├── 任务 1: 文件名 + 大小 + 状态 + 进度条 + 百分比 + 操作按钮
│ ├── 任务 2: ...
│ └── 任务 3: ...
├── 清除已完成按钮(仅在有已完成任务时显示)
└── 组件说明卡片
2.2 数据结构
class DownloadTask {
id: number;
fileName: string; // 文件名
fileSize: string; // 文件大小(文本展示)
progress: number; // 下载进度 0-100
status: string; // 'downloading' | 'paused' | 'completed' | 'failed'
}
DownloadTask 是 class(而非 interface),原因与之前的文章一致——ArkTS 不支持对象展开运算符,需要用工厂方法(withProgress、withStatus、withComplete)创建修改后的新对象:
class DownloadTask {
withProgress(p: number): DownloadTask {
return new DownloadTask(this.id, this.fileName, this.fileSize, p, this.status);
}
withStatus(s: string): DownloadTask {
return new DownloadTask(this.id, this.fileName, this.fileSize, this.progress, s);
}
withComplete(): DownloadTask {
return new DownloadTask(this.id, this.fileName, this.fileSize, 100, 'completed');
}
}
2.3 初始任务
Demo 预置了 3 个下载任务,覆盖三种状态:
| 任务 | 文件 | 大小 | 初始进度 | 状态 |
|---|---|---|---|---|
| 1 | HarmonyOS_SDK_6.1.1.zip | 856 MB | 42% | 下载中 |
| 2 | DevEco_Studio_Setup.dmg | 2.1 GB | 0% | 已暂停 |
| 3 | arkui_component_library.har | 3.8 MB | 100% | 已完成 |
三种状态各有对应的 UI 样式:下载中显示蓝色进度条、已暂停显示灰色进度条、已完成显示绿色进度条。
三、进度条的美学设计
3.1 颜色与状态映射
if (task.status !== 'failed') {
Progress({ value: task.progress, total: 100, type: ProgressType.Linear })
.width('100%')
.height(6)
.color(task.status === 'completed' ? '#52C41A' :
(task.status === 'paused' ? '#CCCCDD' : '#1677FF'))
.backgroundColor('#F2F3F5')
}
三种颜色的语义:
- 蓝色
#1677FF:下载中——积极、进行中 - 灰色
#CCCCDD:已暂停——中性、等待中 - 绿色
#52C41A:已完成——成功、积极完成
轨道背景统一使用 #F2F3F5(浅灰),与页面背景色一致,确保进度条在任何状态下都有清晰的视觉对比。进度条高度设为 6px——足够高以便看清填充状态,又不会在列表中显得过于粗重。
3.2 百分比显示
进度条右侧显示精确百分比:
Text(task.progress.toString().concat('%'))
.fontSize(13)
.fontColor(task.status === 'completed' ? '#52C41A' :
(task.status === 'paused' ? '#CCCCDD' : '#1677FF'))
.fontWeight(FontWeight.Medium)
.width(40)
.textAlign(TextAlign.End)
百分比文字的颜色与进度条颜色一致,形成"进度条-百分比"的视觉连线。宽度固定为 40px 并右对齐,确保不同进度的数值(“7%”、“42%”、“100%”)在垂直方向上对齐,不会因文字宽度变化而左右晃动。
3.3 状态标签
每个任务卡片的右上角有一个状态标签:
Text(this.getStatusText(task.status))
.fontSize(11)
.fontColor(this.getStatusColor(task.status))
.padding({ top: 3, bottom: 3, left: 8, right: 8 })
.borderRadius(8)
.backgroundColor(this.getStatusColor(task.status).concat('18'))
标签使用主题色文字 + 低透明度同色背景(.concat('18') 追加 10% 不透明度的 alpha 通道),形成优雅的彩色标签。四个状态的映射:

四、下载任务操作
4.1 暂停与继续
每个进行中或已暂停的任务都有一个"暂停"或"继续"按钮:
if (task.status === 'downloading' || task.status === 'paused') {
Text(task.status === 'downloading' ? '⏸ 暂停' : '▶ 继续')
.onClick(() => { this.togglePause(task.id); })
}
togglePause 在两个状态之间切换:
togglePause(id: number): void {
this.tasks = this.tasks.slice().map((task: DownloadTask) => {
if (task.id === id) {
if (task.status === 'downloading') return task.withStatus('paused');
if (task.status === 'paused') return task.withStatus('downloading');
}
return task;
});
this.startSimulation();
}
切换到"继续"后调用 startSimulation() 确保定时器处于运行状态(因为所有任务可能之前都处于暂停/完成状态,定时器已自动停止)。
4.2 取消与删除
进行中的任务显示红色"取消"按钮,已完成的任务显示灰色"删除"按钮:
if (task.status !== 'completed') {
Text('取消')
.fontColor('#FF4D4F')
.backgroundColor('#FFF1F0')
.onClick(() => { this.removeTask(task.id); })
}
if (task.status === 'completed') {
Text('删除')
.fontColor('#BBBBCC')
.backgroundColor('#F8F9FA')
.onClick(() => { this.removeTask(task.id); })
}
"取消"使用红色调(文字 #FF4D4F + 背景 #FFF1F0),暗示这是一个"破坏性"操作。"删除"使用灰色,表明这是一个中性的清理操作。两者调用的 removeTask 是同一个方法——通过 slice().filter() 创建不包含该 ID 的新数组:
removeTask(id: number): void {
this.tasks = this.tasks.slice().filter((task: DownloadTask) => task.id !== id);
}
4.3 添加下载
用户点击"+ 添加"按钮后,从预设库中按顺序选取文件添加到下载队列:
addDownload(): void {
let downloads = this.getPresetDownloads();
let existing = this.tasks.length;
let idx = existing % downloads.length;
let d = downloads[idx];
let task = new DownloadTask(this.nextId, d.name, d.size, 0, 'downloading');
this.nextId++;
this.tasks = this.tasks.slice().concat(task);
this.startSimulation();
}
使用 existing % downloads.length 循环选取预设文件——第 4、9、14… 次添加会回到第一个预设文件。通过 slice().concat(task) 追加新任务(而非 push)以触发 @State 响应式更新。添加后调用 startSimulation() 启动定时器。
预设库包含 5 个不同类型和大小文件:
| 文件名 | 大小 | 模拟场景 |
|---|---|---|
| harmonyos_docs_2026.pdf | 24 MB | 小文档 |
| sample_project_template.zip | 4.5 MB | 小压缩包 |
| media_resources_bundle.tar | 320 MB | 中型资源包 |
| debug_symbols_package.7z | 1.8 GB | 大型包 |
| ui_mockup_design.fig | 18 MB | 设计文件 |
4.4 清除已完成
当列表中存在已完成任务时,底部显示"清除已完成任务"按钮:
if (this.tasks.filter((task: DownloadTask) =>
task.status === 'completed').length > 0) {
Row() {
Text('清除已完成任务')
}
.onClick(() => { this.clearCompleted(); })
}
clearCompleted 过滤掉所有已完成状态的任务:
clearCompleted(): void {
this.tasks = this.tasks.slice()
.filter((task: DownloadTask) => task.status !== 'completed');
}
这是一个批量清理操作——在下载管理器中,用户通常会在多个文件下载完成后一次性清理,而不是逐个删除。
五、标题栏的动态计数
标题栏右侧显示进行中的任务数:
Text(this.getActiveCount().toString().concat(' 个进行中'))
getActiveCount(): number {
return this.tasks.filter((task: DownloadTask) =>
task.status === 'downloading' || task.status === 'paused').length;
}
当用户添加新下载时,数字增加;当任务完成或取消时,数字减少。这个动态计数让用户无需滚到列表底部就能感知下载队列的状态。
六、定时器的自动停止
定时器在两种情况下自动停止:
- 所有任务非下载中:当
startSimulation的回调中检测不到任何status === 'downloading'的任务时,自动clearInterval:
if (!hasActive) {
this.stopSimulation();
}
- 页面销毁时:
aboutToDisappear中调用stopSimulation
这意味着定时器只在"需要时"运行——有下载任务在进行。这种设计避免了不必要的 CPU 开销和电池消耗。当用户暂停最后一个下载任务后,定时器立即停止;当用户恢复下载或添加新任务时,startSimulation() 重新启动定时器。
七、交互流程演示
7.1 初始状态
进入页面,3 个预置任务显示在列表中。任务 1(SDK)的进度条在 42% 处,蓝色进度条以随机速度推进。任务 2(DevEco Studio)显示灰色进度条和"已暂停"状态。任务 3(组件库)显示绿色进度条和"已完成"状态。标题栏显示"2 个进行中"。
7.2 自动完成
约 30-40 秒后,任务 1 的进度条到达 100%,自动变为绿色,状态变为"已完成"。标题栏计数变为"1 个进行中"。
7.3 暂停与继续
点击任务 1 的"⏸ 暂停"按钮——进度条变为灰色,状态变为"已暂停"。标题栏计数变为"0 个进行中",定时器自动停止。
点击"▶ 继续"按钮——进度条恢复蓝色,定时器重新启动。起止在之前暂停的进度值继续推进。
7.4 添加与取消
点击"+ 添加"按钮 3 次,新增 3 个下载任务出现在列表底部,进度从 0% 开始推进。标题栏计数更新为"4 个进行中"。
点击其中某个任务的"取消"按钮——该任务从列表中移除。标题栏计数自动更新。
7.5 清除已完成
点击底部的"清除已完成任务"——所有绿色状态的任务被移除,列表变干净。Toast 提示"已清除已完成任务"。
八、总结
本文通过"下载管理器"这个实战案例,全面讲解了 ArkUI Progress 进度条组件的使用方法。核心知识点包括:
- Progress 五种样式:Linear(线形)、Ring(环形)、ScaleRing(刻度环形)、Eclipse(月食)、Capsule(胶囊)
- Progress 配置:
value/total/.color()/.backgroundColor()/.height() - 定时器模拟进度:
setInterval+ 随机增量 + 自动完成检测 - 定时器生命周期:
aboutToAppear启动 +aboutToDisappear清理 + 空闲自动停止 - 任务状态管理:下载中 / 已暂停 / 已完成 / 失败,颜色语义化映射
- 批量操作:添加下载、暂停/继续、取消/删除、清除已完成
- ArkTS 不可变更新:
slice().map()+ 工厂方法替代展开运算符
进度条看似简单,但用好它需要理解的不只是 API——更是状态管理、定时器生命周期和视觉一致性的综合能力。一个好的进度指示不仅是"从 0 到 100"的填充动画,更是让用户在等待中保持耐心的心理工具。ArkUI 的 Progress 组件提供了灵活的样式和配置选项,让开发者可以针对不同场景选择最合适的呈现方式。
更多推荐


所有评论(0)