HarmonyOS ArkUI Progress 进度条:5 种类型与动画演示

系列:鸿蒙 HarmonyOS 6.1 新特性实战 · 第 36 篇

Progress 组件支持 5 种不同的视觉类型,从线形到环形再到胶囊形,配合定时器可实现丝滑的进度动画。本篇完整演示所有类型,并给出通用的进度动画模式和生命周期清理最佳实践。

运行效果

初始状态,展示 5 种进度条类型(进度 0%):

点击"开始演示"后,进度动画进行中:

一、Progress 5 种类型

typescript 复制代码
// Linear 线形(最常用,适合页面顶部加载进度)
Progress({ value: 60, total: 100, type: ProgressType.Linear })
  .width('100%').height(8)
  .color('#0066ff').backgroundColor('#e0e8ff')

// Ring 环形(适合圆形 Loading 指示)
Progress({ value: 60, total: 100, type: ProgressType.Ring })
  .width(80).height(80)
  .color('#0066ff').backgroundColor('#e0e8ff')
  .style({ strokeWidth: 8 })

// Eclipse 月食形(视觉特殊,用于特定场景)
Progress({ value: 60, total: 100, type: ProgressType.Eclipse })
  .width(80).height(80)
  .color('#8e44ad').backgroundColor('#f0e0ff')

// ScaleRing 刻度环形(带刻度线,精密进度)
Progress({ value: 60, total: 100, type: ProgressType.ScaleRing })
  .width(80).height(80)
  .color('#e67e22').backgroundColor('#fff3e0')
  .style({ strokeWidth: 8, scaleCount: 20, scaleWidth: 3 })

// Capsule 胶囊形(适合下载进度、文件传输)
Progress({ value: 60, total: 100, type: ProgressType.Capsule })
  .width('100%').height(32)
  .color('#27ae60').backgroundColor('#e0ffe8')

二、Ring + Stack 显示百分比数字

环形进度条中间叠加文字是常见需求,用 Stack 实现:

typescript 复制代码
Stack() {
  Progress({ value: this.progress, total: 100, type: ProgressType.Ring })
    .width(80).height(80)
    .color('#e74c3c').backgroundColor('#ffe0e0')
    .style({ strokeWidth: 8 })
  Text(this.progress.toString() + '%')
    .fontSize(14).fontColor('#e74c3c').fontWeight(FontWeight.Bold)
}

三、进度动画:setInterval + aboutToDisappear

进度动画核心是用 setInterval 定期更新 @State,页面销毁时必须清理定时器:

typescript 复制代码
@State progress: number = 0
@State running: boolean = false
private timer: number = -1

// 必须在 aboutToDisappear 清理定时器
aboutToDisappear(): void {
  if (this.timer >= 0) { clearInterval(this.timer) }
}

startProgress(): void {
  this.progress = 0
  this.running = true
  this.timer = setInterval(() => {
    this.progress += 2
    if (this.progress >= 100) {
      this.progress = 100
      this.running = false
      clearInterval(this.timer)
      this.timer = -1
    }
  }, 60)  // 每 60ms +2%,约 3 秒完成
}

为什么 timer 初始值用 -1? 避免用 0 导致与合法 timer ID 冲突(部分系统会返回 0 作为首个 timer ID),用 -1 作为"未启动"哨兵值更安全。

四、style 属性

.style() 支持的参数因类型而异:

typescript 复制代码
// Linear / Capsule
.style({ strokeWidth: 14, enableSmoothEffect: true })

// Ring
.style({ strokeWidth: 8 })

// ScaleRing
.style({ strokeWidth: 8, scaleCount: 20, scaleWidth: 3 })

enableSmoothEffect: true 开启线形进度条的平滑动效(默认开启)。

完整代码

typescript 复制代码
@Entry
@Component
struct Index {
  @State progress: number = 0
  @State running: boolean = false
  private timer: number = -1

  aboutToDisappear(): void {
    if (this.timer >= 0) { clearInterval(this.timer) }
  }

  startProgress(): void {
    this.progress = 0
    this.running = true
    this.timer = setInterval(() => {
      this.progress += 2
      if (this.progress >= 100) {
        this.progress = 100
        this.running = false
        clearInterval(this.timer)
        this.timer = -1
      }
    }, 60)
  }

  build() {
    Scroll() {
      Column({ space: 20 }) {
        Text('Progress 全类型进度条')
          .fontSize(22).fontWeight(FontWeight.Bold).fontColor('#1a1a1a')

        Text('当前进度:' + this.progress.toString() + '%')
          .fontSize(16).fontColor('#0066ff').fontWeight(FontWeight.Bold)

        Button(this.running ? '进行中...' : '开始演示')
          .width('100%').height(48).backgroundColor(this.running ? '#aaa' : '#0066ff').fontColor('#fff')
          .enabled(!this.running).onClick(() => { this.startProgress() })

        // Linear
        Column({ space: 8 }) {
          Text('一、Linear 线形').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
          Progress({ value: this.progress, total: 100, type: ProgressType.Linear })
            .width('100%').height(8).color('#0066ff').backgroundColor('#e0e8ff')
          Progress({ value: this.progress, total: 100, type: ProgressType.Linear })
            .width('100%').height(14).color('#27ae60').backgroundColor('#e0ffe8')
            .style({ strokeWidth: 14, enableSmoothEffect: true })
        }
        .padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
        .border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)

        // Ring
        Column({ space: 8 }) {
          Text('二、Ring 环形').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
          Row({ space: 24 }) {
            Column({ space: 4 }) {
              Progress({ value: this.progress, total: 100, type: ProgressType.Ring })
                .width(80).height(80).color('#0066ff').backgroundColor('#e0e8ff')
                .style({ strokeWidth: 8 })
              Text('默认').fontSize(12).fontColor('#666')
            }
            Column({ space: 4 }) {
              Stack() {
                Progress({ value: this.progress, total: 100, type: ProgressType.Ring })
                  .width(80).height(80).color('#e74c3c').backgroundColor('#ffe0e0')
                  .style({ strokeWidth: 8 })
                Text(this.progress.toString() + '%')
                  .fontSize(14).fontColor('#e74c3c').fontWeight(FontWeight.Bold)
              }
              Text('叠加文字').fontSize(12).fontColor('#666')
            }
          }
        }
        .padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
        .border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)

        // Eclipse + ScaleRing
        Column({ space: 8 }) {
          Text('三、Eclipse 月食 / ScaleRing 刻度环').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
          Row({ space: 24 }) {
            Column({ space: 4 }) {
              Progress({ value: this.progress, total: 100, type: ProgressType.Eclipse })
                .width(80).height(80).color('#8e44ad').backgroundColor('#f0e0ff')
              Text('Eclipse').fontSize(12).fontColor('#666')
            }
            Column({ space: 4 }) {
              Progress({ value: this.progress, total: 100, type: ProgressType.ScaleRing })
                .width(80).height(80).color('#e67e22').backgroundColor('#fff3e0')
                .style({ strokeWidth: 8, scaleCount: 20, scaleWidth: 3 })
              Text('ScaleRing').fontSize(12).fontColor('#666')
            }
          }
        }
        .padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
        .border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)

        // Capsule
        Column({ space: 8 }) {
          Text('四、Capsule 胶囊形').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
          Progress({ value: this.progress, total: 100, type: ProgressType.Capsule })
            .width('100%').height(32).color('#27ae60').backgroundColor('#e0ffe8')
        }
        .padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
        .border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)
      }
      .padding(20).width('100%')
    }
    .width('100%').height('100%').backgroundColor('#f5f5f5')
  }
}

API 速查

属性/方法 说明
Progress({ value, total, type }) 创建进度条
.color('#0066ff') 进度颜色
.backgroundColor('#e0e8ff') 轨道背景色
.style({ strokeWidth, ... }) 样式配置(按类型不同)
ProgressType.Linear 线形
ProgressType.Ring 环形
ProgressType.Eclipse 月食形
ProgressType.ScaleRing 刻度环形
ProgressType.Capsule 胶囊形

小结

  • Linear 是最通用的:加载进度、下载进度首选,简洁明了
  • Ring + Stack = 圆形进度:用 Stack 叠加 Text 显示百分比,是标准做法
  • 定时器必须在 aboutToDisappear 清理:否则页面离开后定时器仍在跑,浪费资源可能崩溃
  • timer 初始值用 -1 而非 0:0 可能是有效 timer ID,用哨兵值 -1 避免误清理

上一篇:Slider 与 Rating 实战 | 下一篇:DatePicker / TimePicker 日期时间选择器完全指南

相关推荐
Jesse_EC5 小时前
从 getStore() 到 execute() —— 单连接 IMAP 管理器的五次迭代记录
后端
摇滚侠5 小时前
《SpringBoot 3:入门与应用实战》第 9 章 使用 WebMvc 开发应用 阅读笔记 20
spring boot·笔记·后端
AI多Agent协作实战派5 小时前
AI多Agent协作系统实战(五十三):同一套系统,Linux沉默,Windows刷屏
后端
那咋乎吧5 小时前
TCP状态机11个状态全梳理(以java netty 结合bio,nio, io多路复用模型为线索在linux上梳理)
后端
用户7813667114455 小时前
RGW 对象多版本功能系统架构与代码解析
后端
Z思学5 小时前
Nest 第一步 · 第 3 篇:理解 Controller / Service / Module 三层架构
后端
学长毕业设计5 小时前
基于SpringBoot的校园爱心志愿管理系统(源码+文档+讲解视频)
vue.js·spring boot·后端
IT_陈寒5 小时前
SpringBoot自动配置失效?这个隐式依赖坑了我三天
前端·人工智能·后端
码视野6 小时前
基于 Spring Boot + Vue3 的【城市雨污水管网液位淤积溯源与立交桥下穿隧洞防汛排涝智控中台】设计与实现(含PRD/三端高保真源码/大屏)
java·前端·人工智能·spring boot·后端
小满zs6 小时前
Go语言第十章(指针)
后端·google·go