🎯 目标

封装一个圆环进度展示组件 AnimatedRingProgress,适用于:

  • 展示任务完成率、学习进度、下载进度等

  • 支持从 0% 缓入到目标进度的动画

  • 中心可显示数值或任意插槽内容

  • 支持自定义颜色、线宽、起始角度

  • 后续可拓展为动态呼吸环、分段颜色环、双环组合等


🧱 动效结构示意

⭕️ 动画绘制圆环从 0° → 进度角度
    中心展示:75%

🧰 组件实现:AnimatedRingProgress.ets

@Component
export struct AnimatedRingProgress {
  @Prop value: number = 0                // 当前进度 0~100
  @Prop color: string = '#007DFF'
  @Prop backgroundColor: string = '#E0E0E0'
  @Prop strokeWidth: number = 8
  @Prop size: number = 120
  @Prop duration: number = 800
  @Slot centerContent: () => void

  @State animatedValue: number = 0

  aboutToAppear() {
    this.animateToValue()
  }

  aboutToUpdate() {
    this.animateToValue()
  }

  build() {
    const radius = (this.size - this.strokeWidth) / 2
    const center = this.size / 2
    const angle = 360 * (this.animatedValue / 100)

    Canvas(this.size, this.size)
      .onDraw(ctx => {
        // 背景圆环
        ctx.strokeArc({
          center: { x: center, y: center },
          radius,
          startAngle: 0,
          sweepAngle: 360,
          style: {
            color: this.backgroundColor,
            width: this.strokeWidth,
            cap: StrokeCap.Round
          }
        })

        // 前景进度
        ctx.strokeArc({
          center: { x: center, y: center },
          radius,
          startAngle: -90,
          sweepAngle: angle,
          style: {
            color: this.color,
            width: this.strokeWidth,
            cap: StrokeCap.Round
          }
        })
      })

    // 中心内容
    Stack()
      .width(this.size).height(this.size)
      .position({ x: 0, y: 0 })
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Center) {
      this.centerContent()
    }
  }

  private animateToValue() {
    const start = this.animatedValue
    const end = this.value
    const steps = 30
    const stepTime = this.duration / steps
    let step = 0

    const timer = setInterval(() => {
      step++
      const progress = step / steps
      this.animatedValue = start + (end - start) * progress
      if (step >= steps) {
        clearInterval(timer)
        this.animatedValue = end
      }
    }, stepTime)
  }
}

📦 使用示例

@Entry
@Component
struct DemoRingProgress {
  @State percent: number = 65

  build() {
    Column({ space: 20 }).padding(20).alignItems(HorizontalAlign.Center) {
      AnimatedRingProgress({
        value: this.percent,
        color: '#28C76F',
        size: 140,
        centerContent: () => Text(`${Math.round(this.percent)}%`)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333')
      })

      Button('随机进度').onClick(() => {
        this.percent = Math.floor(Math.random() * 101)
      })
    }
  }
}

✨ 可扩展能力建议

功能 说明
多色渐变圆环 支持颜色渐变,使用 shader: sweepGradient 实现
圆环呼吸/光晕特效 添加 shadow 或额外圆圈动画增强视觉
支持双环/多层进度嵌套 外圈显示总进度,内圈显示子任务进度等组合形式
进度变化数值动画 数字本身也可使用 RollingNumber 滚动显示

📘 下一篇预告

第12篇:【HarmonyOS 5.0.0 或以上】构建拖拽排序组件 DragSortableList:支持拖动换位 / 长按激活 / 平滑过渡动画

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐