参考demo
// CircularSlider.ets
import componentUtils from '@ohos.arkui.componentUtils'
import { JSON } from '@kit.ArkTS'
@Entry
@Component
export struct CircularSlider {
@State @Watch('onCountUpdated') progressNum: number = 98
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private context1: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
@State Max_Num: number = 100
@State angleChange: number = 270 / this.Max_Num;
@State X: number = 60
@State Y: number = 10
@State angle: number = (135 + this.angleChange * this.progressNum) * (Math.PI / 180)
@State circleX: number = 0
@State circleY: number = 0
circleCenterX: number = 60
circleCenterY: number = 60
onCountUpdated(): void {
if (Math.round(this.progressNum * 10) / 10 > this.Max_Num) {
console.info('progressNum:', this.progressNum)
this.progressNum = 0
}
this.setProgress()
}
setProgress = (): void => {
this.context.clearRect(0, 0, 200, 200)
//画底层灰色进度条,数值固定不动
let endAngle: number = this.progressNum //读取当前数值
if (endAngle > this.Max_Num) {
endAngle = 0
} //防止溢出
let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById('flag1'); //获取相对位置信息
console.log('[modePosition]', JSON.stringify(modePosition))
this.circleX = px2vp(modePosition?.localOffset?.x + modePosition.size?.width * 0.5) //flag相对父组件的位置加上自身长度,将px转换成pv
this.circleY = px2vp(modePosition?.localOffset?.x + modePosition.size?.width * 0.5)
console.log('[circleX]', JSON.stringify(this.circleX))
console.log('[circleY]', JSON.stringify(this.circleY))
// 外圈
this.context.beginPath()
this.context.arc(this.circleX, this.circleY, 78, 135 * (Math.PI / 180), 45 * (Math.PI / 180))
this.context.lineWidth = 5
this.context.strokeStyle = "#fda935"
this.context.lineCap = 'round'
this.context.stroke()
//画选中进度条
this.context.beginPath()
let angleChange1: number = (135 + this.angleChange * endAngle + 0.01) * (Math.PI / 180) //计算弧形进度条的结束位置
this.context.arc(this.circleX, this.circleY, 78, 135 * (Math.PI / 180), angleChange1)
this.context.lineWidth = 5
this.context.strokeStyle = "#eeedeb"
this.context.lineCap = 'round'
this.context.stroke()
// 指针
this.context1.clearRect(0, 0, 200, 200)
this.context1.beginPath()
this.context1.moveTo(this.circleCenterX + 50 * Math.cos(this.angle),
this.circleCenterY + 50 * Math.sin(this.angle)) //起点
this.context1.lineTo(this.circleCenterX + 0 * Math.cos(this.angle),
this.circleCenterY + 0 * Math.sin(this.angle)) //终点
this.context1.lineWidth = 3
this.context1.strokeStyle = "#fd6eee4a"
this.context1.lineCap = 'round'
this.context1.stroke()
//画内层虚线进度条
let outerRadius = 70 //外部圆圈半径
let inerRadius = 65 //内部圆圈半径
let addAngle: number = 5 * this.angleChange * (Math.PI / 180) //设置数值每变化1,画一条线,防止过于密集
for (let angle = 135 * (Math.PI / 180); angle <= 405 * (Math.PI / 180); angle += addAngle) {
this.context.beginPath()
this.context.moveTo(this.circleX + outerRadius * Math.cos(angle),
this.circleY + outerRadius * Math.sin(angle)) //起点
this.context.lineTo(this.circleX + inerRadius * Math.cos(angle),
this.circleY + inerRadius * Math.sin(angle)) //终点
this.context.strokeStyle = "#60ffffff"
this.context.lineWidth = 1 //线段宽度
this.context.stroke()
}
}
build() {
RelativeContainer() {
Canvas(this.context)
.width("100%")
.height('100%')
.onReady(() => {
this.setProgress()
})
.id('canvas1')
Row() {
// 圆心(60,60)
Canvas(this.context1)
.width("100%")
.height('100%')
.borderRadius('50%')
.position({ y: 0 })
.onReady(() => {
this.setProgress()
})
}
.width(120)
.height(120)
.borderRadius(60)
.position({ x: 41, y: 41 })
Text(this.progressNum.toString())
.position({ y: '50%', x: '43%' })
.fontSize(18)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
Text('MB/S')
.position({ y: '58%', x: '43%' })
.fontSize(12)
.fontColor(Color.White)
Button('num++')
.onClick((event: ClickEvent) => {
this.progressNum = Number(Math.round(this.progressNum * 10) / 10 + 1)
let angleChange1: number = (135 + this.angleChange * this.progressNum) * (Math.PI / 180)
if (this.angle < angleChange1) {
this.angle += this.angleChange * (Math.PI / 180)
console.log('angle: ' + this.angle)
} else {
this.angle = 135 * (Math.PI / 180)
}
})
.id('btn')
.alignRules({
'bottom': { 'anchor': '__container__', 'align': VerticalAlign.Bottom },
'middle': { 'anchor': '__container__', 'align': HorizontalAlign.Center }
})
}
.height(300)
.width(200)
.id('flag1')
.backgroundColor('#ff9602')
}
}