HarmonyOS 自定义组件之可拖拽圆形进度条

系统 OpenHarmony
在项目开发中,我们经常会用到自定义组件,此处分享一下HarmonyOS中JS如何利用canvas实现自定义组件之可拖拽圆形进度条。

[[443107]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

简介

在项目开发中,我们经常会用到自定义组件,此处分享一下HarmonyOS中JS如何利用canvas实现自定义组件之可拖拽圆形进度条。

效果演示

#星光计划2.0# HarmonyOS 自定义组件之可拖拽圆形进度条-鸿蒙HarmonyOS技术社区

实现思路

官方文档:JS API参考-HarmonyOS应用开发

思路参考: 可拖拽圆形进度条组件(支持移动端))

这里并未采用官方文档说通过element引入到宿主页面的方式;

#星光计划2.0# HarmonyOS 自定义组件之可拖拽圆形进度条-鸿蒙HarmonyOS技术社区

采用上述过程发了bug:canvas首次渲染绘制的不显示;

解决方案: 在页面生命周期onShow的时候,通过js让canvas绘制一次;

  1. onShow() { 
  2.    // Todo 绘制 

1.项目结构

#星光计划2.0# HarmonyOS 自定义组件之可拖拽圆形进度条-鸿蒙HarmonyOS技术社区

2.DragAcr初始化

定义构造函数,声明绘制圆的参数;

  1. export default class DragAcr { 
  2.     constructor(param) { 
  3.         this.initParam(param) 
  4.         this.draw(this.value) 
  5.     } 
  6.  
  7.     initParam(param) { 
  8.         const { 
  9.             el, 
  10.             startAngle = 0, 
  11.             endAngle = 2, 
  12.             width = 252, 
  13.             innerColor = "red"
  14.             outColor = "#08000000"
  15.             innerLineWidth = 1, 
  16.             outLineWidth = 24, 
  17.             counterclockwise = false
  18.             slider = 8, 
  19.             color = ["#ffffff""#0F75F3""#54C8A5""#FEDB00""red"], 
  20.             sliderColor = "#ffffff"
  21.             sliderBorderColor = "blue"
  22.             value = 0, 
  23.             change = (v) => { 
  24.                 console.log(v) 
  25.             }, 
  26.             textShow = true
  27.         } = param; 
  28.          
  29.            this.el = el; 
  30.         this.width = width; 
  31.         this.height = width; 
  32.         this.center = this.width / 2 
  33.         this.outLineWidth = outLineWidth; 
  34.         this.radius = this.width / 2 - this.outLineWidth / 2; 
  35.         // this.ctx = el.getContext("2d"); 
  36.         this.ctx = this.el.getContext('2d', { 
  37.             antialias: true 
  38.         }); 
  39.  
  40.         this.startAngle = startAngle; 
  41.         this.endAngle = endAngle; 
  42.         this.innerColor = innerColor; 
  43.         this.outColor = outColor; 
  44.         this.innerLineWidth = innerLineWidth; 
  45.         this.counterclockwise = counterclockwise; 
  46.         this.slider = slider; 
  47.         this.color = color; 
  48.         this.sliderColor = sliderColor; 
  49.         this.sliderBorderColor = sliderBorderColor; 
  50.         this.value = value; 
  51.         this.textShow = textShow; 
  52.         this.change = change; 
  53.         this.isDown = false

3.DragAcr绘制

canvas的API参考:canvas组件-画布组件

根据当前进度 分段式的绘制需要的各个小控件;

  1. // 绘图 
  2.  draw(value) { 
  3.         console.log(TAG + ';draw  value:' + value); 
  4.         if (value == undefined) { 
  5.             value = this.value; 
  6.         } else { 
  7.             this.value = value; 
  8.         } 
  9.  
  10.         this.ctx.clearRect(0, 0, this.width, this.width); 
  11.         this.ctx.save(); 
  12.  
  13.         let startDeg = this.counterclockwise ? Math.PI * (2 - this.startAngle) : Math.PI * this.startAngle 
  14.         let endDeg = this.counterclockwise ? Math.PI * (2 - this.endAngle) : Math.PI * this.endAngle 
  15.  
  16.  
  17.         // 绘制背景圆 
  18.         this.ctx.beginPath(); 
  19.         this.ctx.arc(this.center, this.center, this.radius, startDeg, 
  20.             endDeg, this.counterclockwise); 
  21.         this.ctx.strokeStyle = this.outColor; 
  22.         this.ctx.lineCap = "round"
  23.         this.ctx.lineWidth = this.outLineWidth; 
  24.         this.ctx.stroke(); 
  25.  
  26.         let Deg = this.valToDeg(value) 
  27.         this.drawOne(startDeg, value); 
  28.  
  29.         if (value > 25) { 
  30.             // 绘制可变圆弧 
  31.             this.drawTwo(value); 
  32.         } 
  33.  
  34.         if (value > 50) { 
  35.             // 绘制可变圆弧 
  36.             this.drawThree(value); 
  37.         } 
  38.  
  39.         if (value > 75) { 
  40.             this.drawFour(value) 
  41.         } 
  42.  
  43.         // 绘制滑块bar 
  44.         this.P = this.DegToXY(Deg) 
  45.         this.ctx.beginPath(); 
  46.         this.ctx.moveTo(this.center, this.center,); 
  47.         this.ctx.arc(this.P.x, this.P.y, this.outLineWidth / 2, 0, Math.PI * 2, false); // 绘制滑块内侧 
  48.         this.ctx.fillStyle = this.sliderBorderColor; 
  49.         this.ctx.fill(); 
  50.         this.ctx.beginPath(); 
  51.         this.ctx.moveTo(this.center, this.center); 
  52.         this.ctx.arc(this.P.x, this.P.y, this.slider, 0, Math.PI * 2, false); // 绘制滑块 
  53.         this.ctx.fillStyle = this.sliderColor; 
  54.         this.ctx.fill(); 
  55.  
  56.         // 文字 
  57.         if (this.textShow) { 
  58.             this.ctx.font = '60px HarmonyHeiTi, HarmonyHeiTi-Medium'
  59.             this.ctx.fillStyle = "#000000"
  60.             this.ctx.textAlign = "center" 
  61.             this.ctx.textBaseline = "middle"
  62.             this.ctx.fillText(this.value + "", this.center, this.center); 
  63.         } 
  64.  
  65.         //  this.drawLine(); 
  66.     } 

4.DragAcr手势监听

手势按下,手势移动,手势抬起的事件处理

  1. OnMouseMove(evt) { 
  2.     if (!this.isDown) return
  3.     let evpoint = {}; 
  4.     evpoint.x = this.getx(evt); 
  5.     evpoint.y = this.gety(evt); 
  6.     let point = this.spotchangeXY(evpoint); 
  7.     let deg = this.XYToDeg(point.x, point.y); 
  8.     //   console.log(TAG + '; OnMouseMove deg XYToDeg ...' + deg); 
  9.     deg = this.counterclockwise ? deg : Math.PI * 2 - deg; 
  10.     //  console.log(TAG + '; OnMouseMove deg...' + deg); 
  11.  
  12.     let val = (deg / Math.PI - this.startAngle) / (this.endAngle - this.startAngle) * 100 
  13.     val = Math.round(val) 
  14.     //  console.log(TAG + '; OnMouseMove val:' + val); 
  15.     if (val < 0) val = 100 + val; 
  16.     if (val <= 0) val = 0; 
  17.     if (val > 100) { 
  18.         if (this.value > 75) { 
  19.             val = 100; 
  20.         } else { 
  21.             val = val - 100; 
  22.         } 
  23.     } 
  24.     if (val > 75) { 
  25.         if (this.value < 25) { 
  26.             val = 0; 
  27.         } 
  28.     } 
  29.  
  30.     //    console.log(TAG + '; OnMouseMove val2:' + val); 
  31.     if (Math.abs(val - this.value) > 10) return
  32.     //   console.log(TAG + '; OnMouseMove val:' + val); 
  33.     this.animate = requestAnimationFrame(this.draw.bind(this, val)); 
  34.     if (this.value != Math.round(val)) { 
  35.         this.value = Math.round(val); 
  36.         this.change(this.value) 
  37.     } 
  38.     //   console.log(TAG + '; OnMouseMove end...'); 
  39.  
  40. OnMouseDown(evt) { 
  41.     let range = 10; 
  42.     let X = this.getx(evt); 
  43.     let Y = this.gety(evt); 
  44.     let P = this.P 
  45.  
  46.     let minX = P.x - this.slider - range; 
  47.     let maxX = P.x + this.slider + range; 
  48.     let minY = P.y - this.slider - range; 
  49.     let maxY = P.y + this.slider + range; 
  50.  
  51.     if (minX < X && X < maxX && minY < Y && Y < maxY) { //判断鼠标是否在滑块上 
  52.         this.isDown = true
  53.     } else { 
  54.         this.isDown = false
  55.     } 
  56.     console.log(TAG + 'OnMouseDown end...'); 
  57.  
  58. OnMouseUp() { //鼠标释放 
  59.     const _this = this 
  60.     cancelAnimationFrame(_this.animate); 
  61.     this.isDown = false 
  62.     console.log(TAG + 'OnMouseUp end...'); 

5.使用方法

  1. index.hml文件 
  2. <div  class="container"
  3.     
  4.     <canvas ref="canvas2" 
  5.             style="width : 252px; height : 252px;" 
  6.             @touchstart="canvasTouchStart" 
  7.             on:touchmove="canvasTouchMove" 
  8.             on:touchend="canvasTouchEnd"></canvas> 
  9. </div> 
  10.  
  11. index.js文件 
  12.  
  13. import DragAcr2 from './dragAcr2.js' 
  14.  
  15. export default { 
  16.     dragAcr2: undefined 
  17.     data: { 
  18.      // 出事化值 
  19.      reverb2: 30, 
  20.     } 
  21.      onShow() { 
  22.           // 首次绘制 
  23.         this.initDragAcr2(); 
  24.     }, 
  25.     // 触摸事件 
  26.     canvasTouchStart(msg) { 
  27.         //console.log('dragAcr  canvasTouchStart msg:' + msg); 
  28.         this.dragAcr2.OnMouseDown(msg); 
  29.     }, 
  30.     canvasTouchMove(msg) { 
  31.         //console.log('dragAcr  OnMouseMove msg:' + msg); 
  32.         this.dragAcr2.OnMouseMove(msg); 
  33.     }, 
  34.     canvasTouchEnd(msg) { 
  35.         // console.log('dragAcr  canvasTouchEnd msg:' + msg); 
  36.         this.dragAcr2.OnMouseUp(msg); 
  37.     }, 
  38.  
  39.     initDragAcr2() { 
  40.         const el = this.$refs.canvas2; 
  41.         if (this.dragAcr2 == undefined) { 
  42.             this.dragAcr2 = new DragAcr2({ 
  43.                 el: el, 
  44.                 value: this.reverb2, 
  45.                 change: (v) => { 
  46.                     console.log(`value:${v}`) 
  47.                 } 
  48.             }) 
  49.         } 
  50.     } 

总结

1,目前在API6及一下手机,canvas绘制时会是屏幕闪烁(API7远程模式无此现象);

2,无论什么语言,思路都是大体相同,绘制,手势,事件分发等。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2017-03-14 15:09:18

AndroidView圆形进度条

2021-09-06 14:58:23

鸿蒙HarmonyOS应用

2022-09-09 14:47:50

CircleArkUI

2021-12-07 18:23:50

自定义进度条分段式

2021-01-11 11:36:23

鸿蒙HarmonyOSApp开发

2022-04-24 14:56:53

容器组件StackTS

2021-11-01 10:21:36

鸿蒙HarmonyOS应用

2021-09-27 10:43:18

鸿蒙HarmonyOS应用

2023-07-18 15:49:22

HTMLCSS

2022-06-30 14:02:07

鸿蒙开发消息弹窗组件

2022-07-15 16:45:35

slider滑块组件鸿蒙

2022-06-20 15:43:45

switch开关鸿蒙

2015-07-31 11:19:43

数字进度条源码

2021-12-24 15:46:23

鸿蒙HarmonyOS应用

2022-07-12 16:56:48

自定义组件鸿蒙

2022-02-17 14:51:39

HarmonyOSJSPAI开发canvas画布

2022-04-24 15:17:56

鸿蒙操作系统

2022-05-20 14:34:20

list组件鸿蒙操作系统

2011-07-05 15:16:00

QT 进度条

2023-02-20 15:20:43

启动页组件鸿蒙
点赞
收藏

51CTO技术栈公众号