49 匹配度圆环:MatchRing 环形进度图绘制

发布时间:2026/7/11 5:46:10
49 匹配度圆环:MatchRing 环形进度图绘制 49 匹配度圆环MatchRing 环形进度图绘制前言图49 匹配度圆环MatchRing 环形进度图绘制 运行效果截图HarmonyOS NEXT环形进度图是一种简洁直观的数据可视化形式。在鹿鹿·笔迹心理分析App 的双人合盘页面中MatchRing组件以百分比圆环展示两人的匹配程度配合品牌色渐变和端点圆点装饰让匹配度一目了然。本文以 [MatchRing.ets](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/common/components/MatchRing.ets) 为例详细解析 Canvas 环形进度图的绘制。鸿蒙官方·Canvas arc APIdeveloper.huawei.com项目源码[MatchRing.ets](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/common/components/MatchRing.ets)图MatchRing 环形进度图绘制——底层灰色轨道 渐变进度弧 端点圆点matchScore 0-100底层轨道灰色完整圆弧计算进度角度score / 100 × 2π渐变进度弧createLinearGradient arc端点装饰arc 小圆点中心文字百分比数值入场动画drawProgress 0→1一、组件结构1.1 接口定义Componentexportstruct MatchRing{PropmatchValue:number78// 匹配度 0-100PropringSize:number200// 画布尺寸Proplabel:string匹配度// 中心标签privatecontext:CanvasRenderingContext2DStateWatch(onDrawProgressChange)drawProgress:number0}1.2 最终效果┌───────────────────────┐ │ ╭──────────╮ │ │ ╱ ╭──────╮ ╲ │ │ │ │ 78% │ │ │ │ ╲ ╰──────╯ ╱ │ │ ╰────●─────╯ │ ← 渐变弧 端点圆点 │ 匹配度 % │ └───────────────────────┘二、背景轨道2.1 完整圆环// MatchRing.ets — 背景轨道绘制constWthis.ringSize// 200constcxW/2// 100constcyW/2// 100constradiusW*0.4// 80画布的 40%constlineW14// 环宽度// 背景轨道整圆浅色描边ctx.beginPath()ctx.arc(cx,cy,radius,0,Math.PI*2)// 从 0 到 2π 整圆ctx.strokeStyleAppColors.LINE// #E5D5BCctx.lineWidthlineW ctx.stroke()2.2 尺寸参数参数值说明ringSize200px画布正方形尺寸radius80px40%圆环半径lineW14px圆环轨道宽度cx/cy100px圆心位置三、渐变进度弧3.1 弧线绘制// 起始角度-π/212点钟方向conststart-Math.PI/2// 结束角度起始角度 匹配度对应的弧度constendstart(Math.PI*2*this.matchValue/100)*this.drawProgress// 创建渐变constgradctx.createLinearGradient(0,0,W,W)// 从左上到右下grad.addColorStop(0,AppColors.PRIMARY_LIGHT)// 浅棕色grad.addColorStop(1,AppColors.PRIMARY_DEEP)// 深棕色// 绘制进度弧ctx.beginPath()ctx.arc(cx,cy,radius,start,end)ctx.strokeStylegrad ctx.lineWidthlineW ctx.lineCapround// 圆头端点ctx.stroke()3.2 角度计算// 匹配度 78% → 弧角度 2π × 78/100 ≈ 4.9 rad// 整圆 2π 360°// 1% 3.6°// 起始点-π/212 点钟// 终点-π/2 2π × matchValue/100matchValue|弧角度|显示效果0%|0|只有起点圆点25%|π/2|右下四分之一50%|π|下半圆78%|4.9|接近完整留小缺口100%|2π|闭合整圆3.3 lineCap ‘round’lineCap控制线端点的形状butt ──────── (默认) 平头端点长度精确 round ●───────● 圆头端点端点向外延伸半个线宽 square █───────█ 方头端点端点向外延伸半个线宽在环形进度图中使用round带来两个视觉效果进度弧的起点圆润自然不突兀进度弧的终点配合端点装饰圆点视觉平滑四、端点装饰圆点4.1 圆点绘制// 仅当进度 50% 时显示端点圆点避免过早出现if(this.drawProgress0.5){// 计算弧终点坐标constcosEndMath.cos(end)constsinEndMath.sin(end)constdotRadius5// 终点坐标 圆心 半径 × 方向constdxcxradius*cosEndconstdycyradius*sinEnd// 绘制白色填充圆点 深色边框ctx.beginPath()ctx.arc(dx,dy,dotRadius,0,Math.PI*2)ctx.fillStyle#ffffff// 白色填充ctx.fill()ctx.strokeStyleAppColors.PRIMARY_DEEP// 深色边框ctx.lineWidth2ctx.stroke()}4.2 圆点位置计算终点在弧的结束位置坐标公式 dx cx radius × cos(end) dy cy radius × sin(end) 例如匹配度 78% 时end ≈ -π/2 4.9 角度接近 4.9 rad ≈ 281° 终点在左下方五、中心文本5.1 匹配度数字// 匹配度数值大字加粗ctx.fillStyleAppColors.TEXTctx.fontbold 36px HarmonyOS Sans SCctx.textAligncenterctx.textBaselinemiddlectx.fillText(${this.matchValue},cx,cy-6)// 略微上移5.2 副标题// 百分比标签小字ctx.fillStyleAppColors.TEXT_2ctx.font12px HarmonyOS Sans SCctx.fillText(${this.label}%,cx,cy22)// 在数字下方文字布局示意┌──────┐ │ 78 │ ← bold 36px中心偏上 6px │匹配度%│ ← 12px中心偏下 22px └──────┘六、颜色系统6.1 渐变颜色// 渐变从左上角到右下角constgradctx.createLinearGradient(0,0,W,W)grad.addColorStop(0,AppColors.PRIMARY_LIGHT)// #C9B09Egrad.addColorStop(1,AppColors.PRIMARY_DEEP)// #8A7A6A颜色变量HEX在圆环中的位置PRIMARY_LIGHT#C9B09E弧起点较浅PRIMARY_DEEP#8A7A6A弧终点较深6.2 动态颜色扩展方案可以根据匹配度高低改变渐变颜色functiongetRingGradient(ctx:CanvasRenderingContext2D,value:number,W:number):CanvasGradient{constgradctx.createLinearGradient(0,0,W,W)if(value80){// 高匹配度 → 暖色grad.addColorStop(0,#F4D5C5)grad.addColorStop(1,#D9A689)}elseif(value60){// 中等匹配度 → 品牌色当前方案grad.addColorStop(0,AppColors.PRIMARY_LIGHT)grad.addColorStop(1,AppColors.PRIMARY_DEEP)}else{// 低匹配度 → 冷色grad.addColorStop(0,#C5D4E4)grad.addColorStop(1,#5B7FB6)}returngrad}七、动画实现7.1 展开动画aboutToAppear():void{// 从 12 点方向顺时针展开进度弧animateTo({duration:AppAnimations.RING_DRAW_DURATION,// 1200mscurve:AppAnimations.CURVE_SMOOTH},(){this.drawProgress1})}onDrawProgressChange():void{this.draw()}7.2 动画三个阶段阶段 1 (0-50%) 进度弧从 12 点方向开始顺时针展开 端点圆点隐藏drawProgress 0.5 阶段 2 (50-99%) 进度弧继续展开 端点圆点开始显示drawProgress 0.5 阶段 3 (100%) 进度弧到位 圆点 文字 渐变弧完整呈现八、完整绘制流程8.1 绘制顺序① clearRect(0, 0, W, W) 清除画布 ② 背景轨道整圆 arc → 底层灰色圆环 ③ 渐变进度弧部分 arc → 上层彩色弧 ④ 端点装饰圆点arc fill → 弧终点的白色圆点 ⑤ 中心数字fillText → 匹配度数值 ⑥ 副标题fillText → 匹配度 %8.2 在 DuetReportPage 中的使用// DuetReportPage.ets — 展示双方匹配度MatchRing({matchValue:this.matchScore,// 从数据库计算ringSize:200,label:匹配度})九、MatchRing 参数调整9.1 尺寸比例// 不同场景下的 ringSizeconstsizes{default:200,// DuetReportPage 标准展示compact:140,// 紧凑卡片large:260// 分享海报中心}9.2 线宽建议// 圆环线宽与尺寸的比例建议constrecommendedLineWidthMath.round(this.ringSize*0.07)// ringSize200 → lineW14 ✅// ringSize140 → lineW10 ✅// ringSize260 → lineW18 ✅十、与其他环形进度方案的对比方案适用场景优点缺点Canvas arc本项目自定义 UI完全可控动画丰富需手写绘制逻辑ArkUI Circle 组件简单环形API 简单不支持进度弧SVG circleWeb 场景可缩放Canvas 不适用总结本文完整解析了 MatchRing 环形进度图的绘制背景轨道arc()整圆 浅色描边渐变进度弧arc(开始角度, 结束角度)lineCap round 线性渐变端点圆点计算弧终点坐标 白色填充 深色边框中心文本大字数字 小字标签垂直居中动画控制drawProgress驱动弧从 -π/2 顺时针展开下一篇文章将介绍Canvas 动画与绘制进度驱动——总结三个图表组件中的 Watch animateTo 动画模式。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力参考资源Canvas arc APICanvas createLinearGradientlineCap 端点样式[MatchRing 组件源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/common/components/MatchRing.ets)[DuetReportPage 合盘页源码](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/pages/DuetReportPage.ets)[AppColors 颜色常量](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/common/theme/AppColors.ets)[AppAnimations 动画常量](file:///Users/fiona/Downloads/bijixinli/harmony-app/entry/src/main/ets/common/theme/AppAnimations.ets)HarmonyOS 开发文档七、环形图高级技巧7.1 lineCap 圆形端点使用lineCap round可以让弧形的起点和终点变成圆形视觉效果更柔和ctx.lineCapround// 端点圆形ctx.lineWidthringWidth ctx.arc(cx,cy,radius,startAngle,endAngle)ctx.stroke()7.2 渐变圆弧使用线性渐变让圆弧产生颜色渐变效果constgradientctx.createLinearGradient(cx-radius,cy,cxradius,cy)gradient.addColorStop(0,#FF6B6B)// 起始色玫红gradient.addColorStop(0.5,#FF9500)// 中间色橙色gradient.addColorStop(1,#FFD700)// 结束色金色ctx.strokeStylegradient7.3 圆环宽度参数化将圆环宽度设计为相对于画布尺寸的比例支持响应式缩放constringWidththis.canvasSize*0.08// 圆环宽度为画布尺寸的 8%constradius(this.canvasSize-ringWidth)/2*0.85如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力