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) })
1 回复