HarmonyOS鸿蒙Next中如何解决饼状进度条角度显示错误问题

HarmonyOS鸿蒙Next中如何解决饼状进度条角度显示错误问题

【问题现象】

(1)用Canvas画布,加上进度条来实现饼状的进度图,但是饼状图没有从0开始走进度条,起始状态如下:

点击放大

(2)而且跑完一圈后,如果需要重新开始展示进度,不会立即归零。如下:

点击放大

问题代码如下:

angle: number = 0
build() {
  Column() {
    Canvas(this.context).width(50).height(50).backgroundColor(Color.Pink)
      .onReady(() => {
        this.centerX = this.context.width / 2
        this.centerY = this.context.height / 2
        this.radius = this.context.width / 2
        this.context.translate(this.centerX, this.centerY)
        setInterval(() => {
          if (this.angle <= 360) {
            this.angle++
          } else {
            this.angle = 0
          }
          this.start()
        }, 10)
      })
  }.justifyContent(FlexAlign.Center)
  .height('100%')
  .width('100%')
}

【定位思路】

1. 了解饼状图的构成

  • 饼状图的框架如下:

点击放大

  • 饼状图构成如下:

点击放大

这里的饼状图,由两条直线和一条弧线组成。当两条直线重合时,如何弧线是整个圆的时候,饼状图则是整个圆形,如果弧线长度为0时,则饼状图为空。

  • 三角函数原理如下:

点击放大

这里,会涉及到计算条直线的三个点,其中直线的起点和直线的终点1为固定值,无需动态计算。但是直线终点2需要根据当前的角度,用三角函数的知识来动态计算。

  • CanvasRenderingContext2D:使用CanvasRenderingContext2D在Canvas画布组件上进行绘制,绘制对象可以是图形、文本、线段、图片等。

代码示例如下:

// this.radius为圆的半径
start() {
  this.context.clearRect(-this.radius, -this.radius, this.context.width, this.context.height)
  this.context.beginPath()
  //  设置圆心的位置坐标轴为x=0,y=0(也可以把其他点设置为x=0,y=0,但是把这里设置为圆心是最方便计算的)
  this.context.moveTo(0, 0)
  // 画一条直线,从圆心连到 直线终点1
  this.context.lineTo(0, -this.radius)
  // 画完圆弧的第一条边,开始准备画圆弧,这里需要准备的是圆弧的起始置和终止位置
  // 起始位置为固定值,如上图所示,当前Y=0的位置在中心,所以起始的弧度,沿着圆心向右的那条线,往上走四分之一个圆的弧度即-π/2
  let startAngle = -Math.PI / 2;
  // 终止位置要根据当前的角度,动态算出即π/180*当前的角度angle
  let endAngle = Math.PI / 180 * this.angle;
  // 算出角度后,圆心(x=0,y=0),半径(this.radius),起始弧度(startAngle),终止弧度(endAngle),画出圆弧
  this.context.arc(0, 0, this.radius, startAngle, endAngle)
  // 画出第二条直线,这里上面介绍的三角函数知识可以算出直线终点2的位置对应的x,y轴坐标
  let x = this.centerX * Math.cos(Math.PI / 180 * this.angle);
  let y = this.centerY * Math.sin(Math.PI / 180 * this.angle);
  // 画第二条直线,从圆心,到上面算出来的点
  this.context.lineTo(x, y)
  // 填充已经画好的饼状图
  this.context.fill()
}

【解决方案】

根据以上分析,可以得出结论:

  • 起始位置,应该是两条直线重叠,切弧线长度为0。所以不难算出,此时angle应该是-90。
  • 而终端的位置,两条直线同样重叠,但是弧线的长度是圆的周长。可以算出,此时angle应该是270。

代码示例如下:

angle: number = -90
  .onReady(() => {
    // 根据画布的宽和高来计算圆形的位置,以及半径
    this.centerX = this.context.width / 2
    this.centerY = this.context.height / 2
    this.radius = this.context.width / 2
    this.context.translate(this.centerX, this.centerY)
    setInterval(() => {
      // 未跑完一圈,angle随着时间匀速递增
      if (this.angle <= 270) {
        this.angle++
      } else {
        // 已跑完一圈,归零重新开始
        this.angle = -90
      }
      this.start()
    }, 10)
  })

更多关于HarmonyOS鸿蒙Next中如何解决饼状进度条角度显示错误问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中如何解决饼状进度条角度显示错误问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


start()方法中,确保起始角度为-90度,结束角度为270度。修改angle初始值为-90,并在setInterval中判断angle是否小于等于270,若超过则重置为-90。这样可以确保饼状图从0度开始,且跑完一圈后立即归零。

代码修改如下:

angle: number = -90
.onReady(() => {
  this.centerX = this.context.width / 2
  this.centerY = this.context.height / 2
  this.radius = this.context.width / 2
  this.context.translate(this.centerX, this.centerY)
  setInterval(() => {
    if (this.angle <= 270) {
      this.angle++
    } else {
      this.angle = -90
    }
    this.start()
  }, 10)
})

start()方法中,确保startAngle-Math.PI / 2endAngleMath.PI / 180 * this.angle

start() {
  this.context.clearRect(-this.radius, -this.radius, this.context.width, this.context.height)
  this.context.beginPath()
  this.context.moveTo(0, 0)
  this.context.lineTo(0, -this.radius)
  let startAngle = -Math.PI / 2
  let endAngle = Math.PI / 180 * this.angle
  this.context.arc(0, 0, this.radius, startAngle, endAngle)
  let x = this.centerX * Math.cos(Math.PI / 180 * this.angle)
  let y = this.centerY * Math.sin(Math.PI / 180 * this.angle)
  this.context.lineTo(x, y)
  this.context.fill()
}
回到顶部