仓颉 ArkUI Path2D 路径对象完全指南:从 SVG 路径字符串到 Canvas 绘制实战

原创2026-10-15 18:06:221,325 阅读
文章标签:文档知识库

仓颉 ArkUI Path2D 路径对象完全指南:从 SVG 路径字符串到 Canvas 绘制实战

Path2D 是仓颉语言 ArkUI 框架(kit.ArkUI)中用于描述自定义绘制路径的路径对象,它既支持通过 moveTo、lineTo、bezierCurveTo 等接口逐段构建路径,也支持直接用符合 SVG 路径描述规范的字符串一次性构造复杂路径,最终交由 CanvasRenderingContext2D 的 stroke()、fill()、clip() 等接口完成描边、填充与裁剪。本文以官方 API 文档为骨架,结合本仓库中的画布定制指南与 SVG 路径规范,完整讲解 Path2D 的构造方式、12 个核心方法、与 Canvas 组件的配合流程,并提供可直接运行的仓颉示例,帮助你掌握在 OpenHarmony 应用中绘制自定义图形、组合路径与路径变换的完整能力。

一、Path2D 是什么

在 ArkUI 的 Canvas 体系中,绘制自定义图形有两条路径:

  1. 直接绘制:在 CanvasRenderingContext2D 对象上调用 moveTo/lineTo/arc 等方法描述路径,再调用 stroke()/fill() 进行绘制;
  2. 先构造 Path2D 对象,再绘制:先单独定义 Path2D 对象构造理想的路径,再通过调用 CanvasRenderingContext2D 对象(以及 OffscreenCanvasRenderingContext2D 对象)的 stroke() 接口或者 fill() 接口进行绘制。

Path2D 就是第二种方式中的"路径对象",它支持通过对象自身的接口完成路径描述,并可被多个绘制上下文复用。该类的系统能力为 SystemCapability.ArkUI.ArkUI.Full,起始版本为 22,使用前需先导入模块:

import kit.ArkUI.*

其类声明如下(cj-canvas-drawing-path2d.md):

public class Path2D {
    public init()
    public init(path: String)
}

两种构造方式

构造器 功能 说明
init() 构造一个空的 Path2D 对象 之后通过 moveTo、lineTo、arc、bezierCurveTo 等接口逐段描述路径
init(d: ?String) 使用符合 SVG 路径描述规范的路径字符串构造 Path2D 对象 d 为必填参数,类型为 ?String,格式参考 Path 组件中 SVG 路径描述规范说明

第二种构造方式特别适合复用来自设计稿(如 Figma/SVG 导出的 path 数据)的路径,无需逐行调用接口即可生成完整的复杂路径。

二、Path2D 的 12 个核心方法

Path2D 提供的方法覆盖了路径描述所需的全部基础能力:移动/连线、弧线/圆弧、贝塞尔曲线、椭圆、矩形、闭合路径、路径组合与变换。

2.1 路径基础操作:moveTo / lineTo / closePath

public func moveTo(x: Float64, y: Float64): Unit
public func lineTo(x: Float64, y: Float64): Unit
public func closePath(): Unit
方法 功能 参数说明
moveTo(x, y) 将路径的当前坐标点移动到目标点,移动过程中不绘制线条 x:目标点 X 轴坐标;y:目标点 Y 轴坐标,默认单位 vp
lineTo(x, y) 从当前点绘制一条直线到目标点 同上,坐标为 vp
closePath() 将路径的当前点移回到路径的起点,当前点与起点间画一条直线 若形状已闭合或只有一个点,则此方法不执行任何操作

这组方法对应 SVG 命令中的 M(moveto)、L(lineto)与 Z(closepath)。使用这三个方法即可勾勒任意多边形轮廓。

2.2 弧线与椭圆:arc / arcTo / ellipse

public func arc(
    x: Float64, y: Float64, radius: Float64,
    startAngle: Float64, endAngle: Float64,
    counterclockwise!: ?Bool = None
): Unit

public func arcTo(
    x1: Float64, y1: Float64, x2: Float64, y2: Float64, radius: Float64
): Unit

public func ellipse(
    x: Float64, y: Float64, radiusX: Float64, radiusY: Float64,
    rotation: Float64, startAngle: Float64, endAngle: Float64,
    counterclockwise!: ?Bool = None
): Unit

arc() 绘制弧形路径,参数如下:

参数 类型 必填 说明
x / y Float64 是 弧线圆心的 x、y 坐标值,默认单位 vp
radius Float64 是 弧线的圆半径,默认单位 vp
startAngle Float64 是 弧线的起始弧度,单位弧度(非角度)
endAngle Float64 是 弧线的终止弧度,单位弧度
counterclockwise ?Bool 否 命名参数,是否逆时针绘制圆弧。true 逆时针,false 顺时针,默认 None

arcTo() 依据圆弧经过的两个点与圆弧半径创建圆弧路径:

参数 类型 必填 说明
x1 / y1 Float64 是 圆弧经过的第一个点的 x、y 坐标,默认单位 vp
x2 / y2 Float64 是 圆弧经过的第二个点的 x、y 坐标,默认单位 vp
radius Float64 是 圆弧的圆半径值,默认单位 vp

ellipse() 在规定的矩形区域绘制一个椭圆:

参数 类型 必填 说明
x / y Float64 是 椭圆圆心的 x、y 轴坐标,默认单位 vp
radiusX / radiusY Float64 是 椭圆 x 轴、y 轴的半径长度,默认单位 vp
rotation Float64 是 椭圆的旋转角度,单位弧度
startAngle Float64 是 椭圆绘制的起始点角度,单位弧度
endAngle Float64 是 椭圆绘制的结束点角度,单位弧度
counterclockwise ?Bool 否 命名参数,是否逆时针绘制椭圆,默认 None

注意:arc/ellipse 的角度参数一律使用弧度。绘制整圆/整椭圆时,常用 0.0 到 2π(约 6.28)作为起止角度,例如下方示例中 arc(100.0, 75.0, 50.0, 0.0, 6.28) 即绘制一个完整圆。

2.3 贝塞尔曲线:quadraticCurveTo / bezierCurveTo

public func quadraticCurveTo(cpx: Float64, cpy: Float64, x: Float64, y: Float64): Unit

public func bezierCurveTo(
    cp1x: Float64, cp1y: Float64, cp2x: Float64, cp2y: Float64,
    x: Float64, y: Float64
): Unit
方法 功能 关键参数
quadraticCurveTo 创建二次贝塞尔曲线的路径 cpx/cpy:贝塞尔控制点的 x、y 坐标;x/y:路径结束时的坐标
bezierCurveTo 创建三次贝塞尔曲线的路径 cp1x/cp1y:第一个贝塞尔控制点;cp2x/cp2y:第二个贝塞尔控制点;x/y:路径结束坐标

所有坐标默认单位均为 vp。贝塞尔曲线是绘制圆角、波浪线、平滑曲线等不规则形状的核心手段,对应 SVG 命令中的 Q(二次贝塞尔)与 C(三次贝塞尔)。

2.4 矩形:rect

public func rect(x: Float64, y: Float64, width: Float64, height: Float64): Unit

创建矩形路径,参数为:左上角 x、y 坐标(vp),矩形的宽度与高度(vp)。与 fillRect/strokeRect 不同,rect() 只创建路径而不立即绘制,它把矩形"登记"进当前 Path2D 对象,需要后续配合 stroke()/fill() 才可见——这使矩形可以作为复杂路径的一部分参与组合。

2.5 路径组合与变换:addPath / setTransform

public func addPath(path2D: ?Path2D): Unit

public func setTransform(
    scaleX: ?Float64, skewX: ?Float64, skewY: ?Float64, scaleY: ?Float64,
    translateX: ?Float64, translateY: ?Float64
): Unit

addPath(path2D) 将另一个路径对象添加到当前的路径对象中,参数 path2D 类型为 ?Path2D,路径单位 px。借助该方法可以将基础形状组合成复杂图形,并让同一个子路径在多处复用。

setTransform(...) 对路径对象进行缩放、倾斜和平移的复合操作,六个参数均为必填:

参数 类型 说明
scaleX ?Float64 x 轴方向上的缩放值
skewX ?Float64 x 轴方向上的倾斜值
skewY ?Float64 y 轴方向上的倾斜值
scaleY ?Float64 y 轴方向上的缩放值
translateX ?Float64 x 轴方向上的平移值
translateY ?Float64 y 轴方向上的平移值

注意参数顺序与常规"2D 变换矩阵"顺序一致(scaleX → skewX → skewY → scaleY → translateX → translateY),设置后对该路径对象的整体几何形态生效。若只需旋转、平移等单一项变换,也可以参考 CanvasRenderingContext2D 的 rotate()/translate()/scale() 思路,通过 setTransform 组合实现。

三、SVG 路径描述规范:用字符串构造 Path2D

Path2D("...") 构造器接受的 d 参数遵循 SVG 路径描述规范。该规范的完整命令定义在 Path 组件文档(cj-graphic-drawing-path.md) 中,下表是全部支持的命令:

命令 名称 参数 说明
M moveto (x y) 在给定 (x,y) 坐标处开始一个新的子路径。例如 M 0 0 将 (0,0) 点作为新子路径的起始点
L lineto (x y) 从当前点到给定 (x,y) 坐标画一条线,该坐标成为新的当前点
H horizontallineto x 从当前点绘制一条水平线,等效于将 y 坐标指定为 0 的 L 命令
V verticallineto y 从当前点绘制一条垂直线,等效于将 x 坐标指定为 0 的 L 命令
C curveto (x1 y1 x2 y2 x y) 以 (x1,y1) 为曲线起点控制点、(x2,y2) 为终点控制点,从当前点到 (x,y) 绘制三次贝塞尔曲线
S smoothcurveto (x2 y2 x y) 以 (x2,y2) 为终点控制点绘制三次贝塞尔曲线;若前一个命令是 C 或 S,起点控制点是上一个命令终点控制点相对起点的映射,否则起点控制点与当前点重合
Q quadraticBeziercurve (x1 y1 x y) 以 (x1,y1) 为控制点,从当前点到 (x,y) 绘制二次贝塞尔曲线
T smoothquadraticBeziercurveto (x y) 绘制二次贝塞尔曲线;若前一个命令是 Q 或 T,控制点为上一个命令终点控制点相对起点的映射,否则控制点与当前点重合
A ellipticalArc (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 从当前点到 (x,y) 绘制椭圆弧。椭圆大小与方向由两个半径 (rx,ry) 与 x-axis-rotation(度)定义,large-arc-flag 与 sweep-flag 决定弧的绘制方式
Z closepath none 通过将当前路径连接回当前子路径的初始点来关闭当前子路径

典型用例:commands("M0 20 L50 50 L50 100 Z") 定义了一个三角形——起始于 (0,20),绘制到 (50,50) 的直线,再绘制到 (50,100) 的直线,最后以 Z 绘制 (50,100) 回到 (0,20) 的直线并闭合路径,形成封闭三角形。将这个字符串传给 Path2D("M0 20 L50 50 L50 100 Z"),即可得到等价的 Path2D 对象。

关联参考:Path 绘制组件(Path() 组件本身)的 commands() 属性同样遵循该规范,单位为 px,像素单位转换方法参考像素单位转换说明。Path2D 构造器与其共用一套 SVG 路径语义,理解其一即可触类旁通。

四、把 Path2D 画出来:与 CanvasRenderingContext2D 配合

Path2D 本身只负责"描述",真正上屏需要 Canvas 组件与其渲染上下文。

4.1 搭建画布

在仓颉 ArkUI 中创建 Canvas 画布(详见 Canvas 组件文档):

var settings: RenderingContextSettings = RenderingContextSettings(antialias: true)
var context: CanvasRenderingContext2D = CanvasRenderingContext2D(this.settings)
  • RenderingContextSettings(antialias: true) 创建渲染上下文设置对象,antialias 表示是否启用抗锯齿,默认值为 false;
  • CanvasRenderingContext2D(settings) 创建 2D 渲染上下文;
  • 在 build() 中通过 Canvas(this.context) 承载该上下文,并在 onReady 回调中开始绘制——Canvas 组件构造完成后才会触发 onReady,此时才可安全绘制。

4.2 三种使用方式:stroke / fill / clip

CanvasRenderingContext2D 文档 中与 Path2D 直接相关的接口如下:

// 描边:进行边框绘制操作
public func stroke(): Unit
public func stroke(path: Path2D): Unit

// 填充:根据当前填充样式填充指定路径
public func fill(fillRule!: ?CanvasFillRule = None): Unit
public func fill(path: ?Path2D, fillRule!: ?CanvasFillRule = None): Unit

// 裁剪:根据指定路径进行裁剪
public func clip(fillRule!: ?CanvasFillRule = None): Unit
public func clip(path: ?Path2D, fillRule!: ?CanvasFillRule = None): Unit

三种典型用法:

  1. 描边(stroke):context.stroke(path) 按当前描边样式(strokeStyle、lineWidth 等)勾勒路径轮廓;
  2. 填充(fill):context.fill(path, fillRule) 按当前填充样式(fillStyle)填充路径内部;fillRule 为可选的填充规则,取值见 CanvasFillRule 枚举:EvenOdd(奇偶规则)与 NonZero(非零环绕规则),详见 cj-common-types.md,在路径自交或存在孔洞时,两种规则会得到不同的填充结果;
  3. 裁剪(clip):context.clip(path, fillRule) 将 Path2D 路径设为裁剪区域,此后的绘制只在该区域内可见,是制作异形卡片、蒙版效果的关键手段。

4.3 完整示例一:用 Path2D 接口构造五边形并填充

以下代码来自画布自定义绘制指南,展示了"构造 Path2D → 设置填充样式 → 填充绘制"的完整链路:

package ohos_app_cangjie_entry

import kit.ArkUI.*
import ohos.arkui.state_macro_manage.*

@Entry
@Component
class EntryView {
    private let settings: RenderingContextSettings = RenderingContextSettings(antialias: true)
    private let context: CanvasRenderingContext2D = CanvasRenderingContext2D(this.settings)

    // 使用Path2D的接口构造一个五边形
    var path: Path2D = Path2D()
    func build() {
        Flex(direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center) {
            Canvas(this.context)
                .width(100.percent)
                .height(100.percent)
                .backgroundColor(0XF5DC62)
                .onReady(
                    {
                        =>
                        path.moveTo(150.0, 50.0)
                        path.lineTo(50.0, 150.0)
                        path.lineTo(100.0, 250.0)
                        path.lineTo(200.0, 250.0)
                        path.lineTo(250.0, 150.0)
                        path.closePath()
                        // 设定填充色为蓝色
                        this.context.fillStyle = 0X0097D4
                        // 使用填充的方式,将Path2D描述的五边形绘制在canvas组件内部
                        this.context.fill(path)
                    }
                )
        }.width(100.percent).height(100.percent)
    }
}

要点拆解:

  • Path2D() 空构造后,用 moveTo 落到起点 (150,50),再用 4 次 lineTo 依次连线,最后 closePath() 闭合五边形;
  • fillStyle = 0X0097D4 设置填充色为蓝色(ArkUI 中 ResourceColor 支持十六进制整型字面量);
  • context.fill(path) 一次性填充整个 Path2D 路径。

4.4 完整示例二:用 arc 绘制圆弧后描边

同样来自该指南,演示 Path2D + stroke 的组合:

package ohos_app_cangjie_entry

import kit.ArkUI.*
import ohos.arkui.state_macro_manage.*

@Entry
@Component
class EntryView {
    private let settings: RenderingContextSettings = RenderingContextSettings(antialias: true)
    private let context: CanvasRenderingContext2D = CanvasRenderingContext2D(this.settings)

    var region: Path2D = Path2D()
    func build() {
        Flex(direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center) {
            Canvas(this.context)
                .width(100.percent)
                .height(100.percent)
                .backgroundColor(0XF5DC62)
                .onReady(
                    {
                        =>
                        this.region.arc(100.0, 75.0, 50.0, 0.0, 6.28)
                        this.context.stroke(this.region)
                    }
                )
        }.width(100.percent).height(100.percent)
    }
}

arc(100.0, 75.0, 50.0, 0.0, 6.28) 以 (100,75) 为圆心、半径 50、从 0 弧度到约 6.28(2π)弧度绘制整圆路径,随后 context.stroke(region) 以描边方式输出。

五、实用建议与注意事项

  1. 单位区分:Path2D 各方法(moveTo、lineTo、arc 等)的坐标/半径默认单位为 vp;而 addPath 的参数说明中路径单位为 px。若设备像素比不同,注意换算(参考像素单位转换)。
  2. 角度一律用弧度:arc、ellipse 的起始/结束角度与 rotation 均为弧度制;整圆常用 0.0 ~ 6.28(即 2π)或借助 std.math.MathExtension 的 Float64.GetPI() 计算。
  3. 路径复用:同一 Path2D 对象可以同时用于 stroke(path)、fill(path)、clip(path),也可以作为 addPath 的参数组合进其他路径,适合反复绘制同一图形。
  4. 绘制时机:所有绘制必须在 Canvas 的 onReady 回调中进行,此时组件已构造完成,上下文才可用。
  5. 填充规则:路径自交或含孔洞时,通过 fill(path, fillRule) 显式指定 EvenOdd 或 NonZero 可精确控制镂空区域。

六、延伸阅读

登录后查看全文
CangjieCorpus