引言在移动应用界面设计中并非所有视觉效果都需要依赖图片资源。图标、装饰性元素、数据可视化图表以及各种形状边框都可以通过矢量图形直接在 UI 中绘制——它们不占用额外的安装包空间、不会因屏幕密度变化而模糊并且可以通过代码灵活调整每一个视觉参数。HarmonyOS NEXT 在 ArkUI 中内置了一套完整的声明式 2D 矢量绘图组件Shape— 绘图容器定义坐标系统和全局样式Circle— 圆形通过半径控制Ellipse— 椭圆由宽高独立控制Rect— 矩形支持圆角Polygon— 多边形自动闭合以形成填充区域Polyline— 折线不闭合适合走势图Path— SVG 路径支持 M/L/C/Q/A/Z 全部标准指令与 Canvas 的命令式绘图不同调用 API 绘制状态不可逆Shape 系列是声明式组件——每一种形状都是一个 UI 组件可以直接嵌入build()方法使用属性的方式配置样式并且天然支持状态驱动的动态更新。本文构建一个矢量图形实验室Demo在 7 种 Shape 组件之间切换通过滑块和文本输入实时调节图形参数配合填充色/描边色/描边宽度/虚线/抗锯齿等样式控件直观地展示每种 Shape 的行为和效果。读完本文你将掌握Shape 容器viewPort坐标系统、全局fill/stroke/strokeWidth/antiAlias/strokeDashArrayCircle 与 Ellipse基于width/height的圆形和椭圆绘制Rect矩形 radiusWidth/radiusHeight实现圆角Polygon 与 Polylinepoints数组驱动的多顶点连线闭合与不闭合的差异PathSVG 风格指令字符串——M(移动)、L(直线)、C(三次贝塞尔)、Q(二次贝塞尔)、A(弧线)、Z(闭合)声明式 vs 命令式绘图Shape 与 Canvas 的本质区别各自适用的场景一、Shape 组件体系总览1.1 Shape — 绘图容器Shape是所有矢量形状的父容器。它有两个核心职责定义坐标系统viewPort设置可视区域的宽高和原点偏移设定默认样式fill、stroke、strokeWidth、strokeDashArray、antiAlias会传递给所有子 ShapeShape(){Circle({width:80,height:80})}.width(100%).height(120).viewPort({x:0,y:0,width:200,height:200}).fill(#3B82F6).stroke(#1E40AF).strokeWidth(2).antiAlias(true).strokeDashArray([4,4])viewPort的四个参数含义x/y可视区域左上角在坐标系统中的位置用于平移视口width/height可视区域的尺寸1.2 样式属性 — 六种通用绘制控制所有 Shape 子组件都可以通过以下属性控制外观属性类型说明默认值.fill(color)ResourceColor形状内部填充颜色Color.Black.fillOpacity(value)number填充透明度 (0.0~1.0)1.0.stroke(color)ResourceColor描边颜色Color.Black.strokeWidth(value)number描边宽度 (vp)1.0.strokeDashArray([dash, gap])Arraynumber虚线样式交替的实线段和空白段无.antiAlias(boolean)boolean是否启用抗锯齿true注意strokeDashArray的值是循环的——[4, 4]意味着 4px 实线、4px 空白交替[8, 4, 2, 4]则形成一个长短交替的虚线图案。1.3 与 Canvas 的本质区别维度Shape 声明式绘图Canvas 命令式绘图编程范式声明式描述是什么命令式描述怎么做状态管理State驱动自动重绘手动clearRect 重绘组件树每个形状是 UI 组件所有形状在同一个画布上交互能力天然支持.onClick等组件事件需要手动计算坐标命中检测动画配合animateTo实现属性动画通过requestAnimationFrame逐帧绘制性能图形数量少时高效图形数量多时高效适合场景UI 图标、装饰元素、简单图表游戏、复杂数据可视化、粒子效果选择建议UI 装饰和图标用 Shape游戏和复杂图表用 Canvas。二、Circle — 圆形Circle 是最简单的 Shape 子组件。通过设置width和height为相同值绘制正圆不同值则产生椭圆形。Shape(){Circle({width:120,height:120})}.viewPort({x:0,y:0,width:120,height:120}).fill(#3B82F6)Circle 没有独立的radius属性——半径由width和height决定。如果需要控制半径只需保证width height 2 * radius。三、Ellipse — 椭圆Ellipse 与 Circle 使用相同的构造函数{ width, height }当width ≠ height时自然形成椭圆。Shape(){Ellipse({width:100,height:60})}.viewPort({x:0,y:0,width:100,height:60}).fill(#10B981)椭圆没有独立的 X 轴半径和 Y 轴半径参数——它们由width/2和height/2隐式决定。四、Rect — 矩形与圆角Rect 支持三个属性Rect().width(120)// 矩形宽度 (vp).height(80)// 矩形高度 (vp).radiusWidth(12)// X 方向圆角半径 (vp).radiusHeight(12)// Y 方向圆角半径 (vp)radiusWidth和radiusHeight可以独立设置产生不对称的圆角效果。当两者都设为 0 时就是标准直角矩形设为一个很大的值如 999则接近胶囊形。五、Polygon — 多边形Polygon 通过points数组定义顶点Polygon().points([[x1,y1],[x2,y2],[x3,y3],...])Polygon 会自动闭合——最后一个顶点会自动连接到第一个顶点形成封闭的填充区域。典型三角形示例Shape(){Polygon().points([[60,10],[110,90],[10,90]])}.viewPort({x:0,y:0,width:120,height:100}).fill(#8B5CF6)Polygon 是绘制填充型几何图形的首选三角形、五角星、六边形、箭头等。它天然适合做 UI 中的状态图标和装饰形状。六、Polyline — 折线Polyline 的 API 与 Polygon 完全相同points数组但行为不同——Polyline 不闭合顶点按顺序直线连接最后一个顶点和第一个顶点之间不会自动连线。Shape(){Polyline().points([[10,80],[40,20],[70,60],[100,10]])}.viewPort({x:0,y:0,width:110,height:90}).stroke(#EC4899).strokeWidth(2)Polyline 适合绘制折线图、心电图、价格走势等不需要闭合的线条类图形。由于没有填充通常配合.fill(Color.Transparent)或直接省略填充。Polygon vs Polyline 选择口诀需要填充颜色 → Polygon只需要线条 → Polyline。七、Path — SVG 路径Path 是 Shape 子组件中最强大也最复杂的一个。它通过commands属性接受一个SVG 风格的指令字符串Path().commands(M10 50 L50 10 L90 50 L50 90 Z)7.1 指令速查指令含义参数示例M x y移动到不画线x, yM10 50L x y画直线到x, yL50 10C cx1 cy1 cx2 cy2 x y三次贝塞尔曲线控制点1, 控制点2, 终点C20 10 80 10 90 50Q cx cy x y二次贝塞尔曲线控制点, 终点Q50 0 100 50A rx ry angle large sweep x y弧线半径x, 半径y, 旋转角, 大弧标志, 扫掠方向, 终点A45 45 0 0 1 95 50Z闭合路径无Z7.2 实战示例菱形DiamondM10 50 L50 10 L90 50 L50 90 Z五角星StarM50 5 L63 38 L98 38 L70 58 L80 93 L50 73 L20 93 L30 58 L2 38 L38 38 Z扇形Pie SliceM50 5 A45 45 0 0 1 95 50 L50 50 Z波浪Wave/Cubic BezierM5 90 C5 30 95 30 95 907.3 三次贝塞尔Cvs 二次贝塞尔QC有 2 个控制点可以产生 S 形曲线Q有 1 个控制点只能产生单峰曲线对于大多数 UI 场景的曲线需求圆角、波浪边缘、有机形态二次贝塞尔已经足够——它少一个参数更容易调出想要的效果。7.4 弧线A参数详解A rx ry x-axis-rotation large-arc-flag sweep-flag x yrx, ry椭圆弧的 X/Y 半径x-axis-rotation弧线旋转角度通常为 0large-arc-flag0 小弧≤180°1 大弧180°sweep-flag0 逆时针1 顺时针x, y终点坐标弧线是 Path 中最复杂的指令但掌握了large-arc-flag和sweep-flag的组合就掌握了核心large-arcsweep效果00小弧 逆时针01小弧 顺时针10大弧 逆时针11大弧 顺时针八、实战 Demo矢量图形实验室页面结构矢量图形实验室 ├── 标题栏 — 矢量图形实验室 Shape 标签 ├── 图形类型选择器 — Circle / Ellipse / Rect / Polygon / Polyline / Path ├── 实时渲染预览区 │ ├── 虚线边框画布 │ └── 实时绘制当前选中图形应用所有样式属性 ├── 属性控制区按类型动态变化 │ ├── Circle: 半径滑块 │ ├── Ellipse: 宽度/高度滑块 │ ├── Rect: 宽度/高度/圆角滑块 │ ├── Polygon: 顶点坐标编辑 │ ├── Polyline: 折线坐标编辑 │ └── Path: 路径命令输入 6 个预设 ├── 样式控制区 │ ├── 填充色8 种颜色圆点 │ ├── 描边色8 种颜色圆点 │ ├── 描边宽度0-10 vp 滑块 │ ├── 虚线开关Toggle │ └── 抗锯齿开关Toggle ├── 七种 Shape 组件参考卡片 └── 核心 API 参考 — 15 个关键 API/属性/指令4 个交互点6 种形状切换— 点击图形类型标签实时切换每种形状在预览区以独立渲染方式展示属性滑块调节— 每种形状有专属参数半径/宽高/圆角/坐标/路径通过滑块实时调节预览Path 预设切换— 6 个预设路径菱形/五角星/扇形/波浪/贝塞尔曲线点击立即切换样式自由搭配— 8 色填充 8 色描边 描边宽度 虚线 抗锯齿实时调节实时生效核心代码实现图形类型切换和渲染if(this.shapeType0){// CircleShape(){Circle({width:this.circleRadius*2,height:this.circleRadius*2})}.viewPort({x:this.strokeW,y:this.strokeW,width:this.viewW,height:this.viewH})}if(this.shapeType5){// PathShape(){Path().commands(this.pathCmd)}.viewPort({x:this.strokeW,y:this.strokeW,width:this.viewW,height:this.viewH})}每种形状的样式属性fill/stroke/strokeWidth 等通过 Shape 容器统一设置所以预览区的每个条件分支中Shape 组件的样式链都是相同的。Polygon/Polyline 的坐标解析parsePoints(pts:string):number[][]{letresult:number[][][];letpartspts.split(/[\s,]/);// 按空白和逗号分割for(leti0;i1parts.length;ii2){letxparseFloat(parts[i]);letyparseFloat(parts[i1]);if(!isNaN(x)!isNaN(y))result.push([x,y]);}returnresult;}这个辅助函数将字符串60,10 110,90 10,90解析为 Polygon/Polyline 所需的number[][]格式。Path 预设系统pathPresets:string[][M10 50 L50 10 L90 50 L50 90 Z,// 菱形M50 5 L63 38 L98 38 L70 58 L80 93 L50 73 L20 93 L30 58 L2 38 L38 38 Z,// 五角星M50 5 A45 45 0 0 1 95 50 L50 50 Z,// 扇形M5 50 Q50 5 95 50 Q50 95 5 50,// 双二次贝塞尔M5 90 C5 30 95 30 95 90,// S 形贝塞尔M10 10 L90 10 L90 90 L10 90 Z// 正方形];6 个预设从简单到复杂覆盖了 Path 的全部指令类型M移动、L直线、C三次贝塞尔、Q二次贝塞尔、A弧线、Z闭合。预览效果预期Circle 模式蓝色正圆半径 60vp可通过滑块从 10 调到 90Rect 模式圆角矩形宽 120、高 80、圆角 12三个独立滑块Polygon 模式三角形三点坐标可修改坐标值变为任意多边形Path 模式默认显示菱形M10 50 L50 10...Z可输入任意 SVG 命令样式调整填充色圆点实时切换描边宽度从 0 到 10虚线开关切换实线/虚线抗锯齿效果在 Path 曲线边缘尤其明显关闭后边缘会出现锯齿九、与 CSS SVG / Android VectorDrawable / iOS UIBezierPath 的对比维度CSS/HTML SVGAndroid VectorDrawableiOS UIBezierPathHarmonyOS Shape绘画范式声明式XML/HTML声明式XML命令式Swift API声明式ArkUI 组件路径指令SVG 标准d属性SVG 标准pathData方法调用addLine/to/curveSVG 标准commands字符串圆角矩形rect rx...同 SVGUIBezierPath(roundedRect:)Rect().radiusWidth()多边形polygon points... /同 SVG需手动moveaddLinePolygon().points([[x,y],...])动态更新通过 JS 修改 DOM/React state需代码重建修改 path 后setNeedsDisplayState驱动自动重绘集成方式嵌入 HTMLasSrc()设置给 ImageViewCAShapeLayer.path直接放在 ArkUIbuild()中HarmonyOS 的 Shape 系统继承了 SVG 路径指令的成熟标准同时将每种形状封装为独立的 ArkUI 组件——这种设计让 Shape 同时享受了 SVG 路径的表达能力和 ArkUI 声明式状态管理的自动更新能力。十、总结Shape 组件体系是 HarmonyOS ArkUI 中轻量级矢量绘图的核心工具7 种组件覆盖了从简单几何Circle/Rect到复杂自由路径Path的全部需求声明式建模让每种形状都是一个 UI 组件可以参与State驱动的自动刷新SVG 路径兼容Path 的commands字符串与 Web/CSS 的 SVGd属性完全同构学习一次三端通用样式属性丰富fill/fillOpacity/stroke/strokeWidth/strokeDashArray/antiAlias 六种控制每种都可以动态切换与 Canvas 互补Canvas 适合游戏和复杂数据可视化Shape 适合 UI 装饰、图标和简单图表结合animateTo属性动画Shape 组件可以实现从形状变换到颜色渐变的流畅动画效果结合TransitionEffect可以实现图形的进场退场动画。HarmonyOS 开发者手中的声明式矢量绘图工具箱已经达到了生产级的水准。