鸿蒙开发-想在画布上画画?Canvas、Brush和Pen先学会
HarmonyOS 绘图基础:Canvas、Brush 与 Pen 使用指南 本文介绍了 HarmonyOS 中 2D 绘制的核心组件及其使用方法: 三大核心元素: Canvas 作为画布承载绘制内容 Brush 控制图形填充颜色/透明度 Pen 管理描边样式(颜色/线宽/线帽等) 绘制流程: 创建 Canvas → 配置 Brush/Pen → 挂载到画布 → 执行绘制 → 释放资源 实际应用:
想在 HarmonyOS 上画画?先搞懂 Canvas、Brush 和 Pen
你有没有想过,那些绘图 APP 里画一条线、画一个圆、填个颜色,底层是怎么实现的?
在 HarmonyOS 里,2D 绘制靠的是 ArkGraphics2D 的 drawing 模块。这个模块提供了三个核心角色:
- Canvas(画布):你画画的"纸",所有图形都画在它上面。
- Brush(画刷):控制"填充"——图形内部填什么颜色。
- Pen(画笔):控制"描边"——图形的轮廓线是什么样。
打个比方:Canvas 是一张白纸,Brush 是你手里的马克笔(用来涂色),Pen 是你手里的勾线笔(用来画轮廓)。你想画一个红色填充、黑色边框的圆?先用 Brush 设好红色,再用 Pen 设好黑色,然后告诉 Canvas “画个圆”,就完事了。
今天我们来做一个绘画 APP 的基础功能,看看怎么用这三个类来画各种图形。
下面是 Canvas 绘制的整体流程:
导入模块
import { drawing } from '@kit.ArkGraphics2D';
所有 drawing 相关的类(Canvas、Brush、Pen、Path 等)都在这个模块里。
创建 Canvas
Canvas 需要一个"绘制目标"——它是一个 PixelMap。你可以把 Canvas 想象成一个"画板",PixelMap 就是画板上的"纸"。所有画上去的东西,最终都会写入这个 PixelMap。
import { drawing } from '@kit.ArkGraphics2D';
import { image } from '@kit.ImageKit';
const color = new ArrayBuffer(96);
let opts: image.InitializationOptions = {
editable: true,
pixelFormat: 3,
size: {
height: 4,
width: 6
}
}
image.createPixelMap(color, opts).then((pixelMap) => {
const canvas = new drawing.Canvas(pixelMap);
})
这里创建了一个 6x4 像素的 PixelMap,然后用它创建了 Canvas。为什么 PixelMap 的 editable 要设为 true?因为 Canvas 需要往上面写入数据,如果不可编辑就画不上去。
用 RenderNode 来画
在实际的 ArkUI 页面里,你不太会直接 new Canvas(pixelMap) 来画。更常见的方式是通过 RenderNode——它是 ArkUI 提供的一个自定义绘制节点,可以在 draw 方法里拿到 Canvas:
import { RenderNode } from '@kit.ArkUI';
import { common2D, drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context: DrawContext) {
const canvas = context.canvas;
// 在这里画画...
}
}
draw 方法会在每次 UI 刷新时被调用,context.canvas 就是当前的画布。后面我们的示例都用这种方式。
Brush:控制填充
Brush(画刷)控制的是图形内部的颜色。创建一个 Brush 很简单:
const brush = new drawing.Brush();
设置颜色
Brush 默认是黑色的。你可以用 setColor 改颜色:
// 方式一:传 Color 对象
const color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 };
brush.setColor(color);
// 方式二:直接传四个值(性能更好,推荐)
brush.setColor(255, 255, 0, 0); // alpha, red, green, blue
颜色格式是 ARGB,每个通道值范围 [0, 255]。alpha 是透明度,255 是完全不透明,0 是完全透明。
方式二(直接传四个数字)性能更好,因为它不需要创建 Color 对象。如果你在 draw 方法里频繁设置颜色,优先用方式二。
设置透明度
brush.setAlpha(128); // 半透明
把 Brush 挂到 Canvas 上
设好颜色后,需要把 Brush "挂"到 Canvas 上,Canvas 才知道用什么颜色来填充:
canvas.attachBrush(brush);
// 画图操作...
canvas.detachBrush(); // 用完记得摘下来
为什么要 detach?因为 Canvas 会一直记住当前挂的 Brush。如果你画完红色矩形后想画蓝色的,不摘掉旧的 Brush,新设的颜色就不会生效。用完就摘,是个好习惯。
Pen:控制描边
Pen(画笔)控制的是图形的轮廓线。用法和 Brush 几乎一样:
const pen = new drawing.Pen();
pen.setColor(255, 0, 0, 255); // 蓝色
pen.setStrokeWidth(5); // 线宽 5 像素
canvas.attachPen(pen);
// 画图操作...
canvas.detachPen();
Pen 的独有属性
Pen 比 Brush 多了一些描边相关的设置:
线宽:
pen.setStrokeWidth(5); // 5 像素宽
线帽(线条端点的样式):
pen.setStrokeCap(drawing.CapType.ROUND_CAP); // 圆头
pen.setStrokeCap(drawing.CapType.SQUARE_CAP); // 方头
pen.setStrokeCap(drawing.CapType.FLAT_CAP); // 平头(默认)
连接样式(两条线相交时的样式):
pen.setStrokeJoin(drawing.JoinStyle.MITER_JOIN); // 尖角
pen.setStrokeJoin(drawing.JoinStyle.ROUND_JOIN); // 圆角
pen.setStrokeJoin(drawing.JoinStyle.BEVEL_JOIN); // 平角
虚线(通过 PathEffect 实现,后面文章会讲)。
画矩形
绘制时需要根据需求选择挂载 Brush、Pen 或两者都挂,下面是选择逻辑:
好,Brush 和 Pen 都准备好了,开始画图。最简单的就是矩形:
class DrawingRenderNode extends RenderNode {
draw(context: DrawContext) {
const canvas = context.canvas;
const pen = new drawing.Pen();
pen.setStrokeWidth(5);
pen.setColor({ alpha: 255, red: 255, green: 0, blue: 0 });
canvas.attachPen(pen);
canvas.drawRect({ left: 0, right: 100, top: 0, bottom: 80 });
canvas.detachPen();
}
}
drawRect 接收一个 Rect 对象,包含 left、right、top、bottom 四个值,定义了矩形的位置和大小。
从 API 12 开始,还有一种性能更好的写法,直接传四个数字:
canvas.drawRect(0, 0, 100, 80); // left, top, right, bottom
如果你只想填充不想描边,就只挂 Brush;只想描边不想填充,就只挂 Pen;两个都要就两个都挂:
// 红色填充 + 蓝色描边
const brush = new drawing.Brush();
brush.setColor(255, 255, 0, 0);
canvas.attachBrush(brush);
const pen = new drawing.Pen();
pen.setColor(255, 0, 0, 255);
pen.setStrokeWidth(3);
canvas.attachPen(pen);
canvas.drawRect(10, 10, 200, 150);
canvas.detachBrush();
canvas.detachPen();
画圆角矩形
const roundRect = new drawing.RoundRect(
{ left: 10, top: 10, right: 200, bottom: 150 },
20, 20 // x 方向和 y 方向的圆角半径
);
canvas.drawRoundRect(roundRect);
圆角半径越大,角越圆。如果你想做那种"胶囊形"的按钮,把圆角半径设成高度的一半就行。
画圆
canvas.drawCircle(100, 100, 50); // 圆心(100,100),半径50
三个参数:圆心 x 坐标、圆心 y 坐标、半径。如果半径小于等于 0,什么都不画。
画椭圆
canvas.drawOval({ left: 10, top: 10, right: 200, bottom: 100 });
椭圆的形状由它的外切矩形决定——矩形多扁,椭圆就多扁。
画弧线
canvas.drawArc({ left: 10, top: 10, right: 200, bottom: 200 }, 0, 90);
三个参数:外切矩形、起始角度(度数)、扫描角度(度数)。起始角度 0 是 3 点钟方向,顺时针为正。上面这段画的是一个从 0 度到 90 度的四分之一圆弧。
如果扫描角度的绝对值大于 360,就变成画整个椭圆了。
画直线
canvas.drawLine(10, 10, 200, 200); // 从(10,10)到(200,200)
注意:画直线只有描边效果,没有填充效果。所以你需要挂 Pen,Brush 对直线没用。
清空画布
如果你想把画布"擦干净",用 clear 方法:
canvas.clear({ alpha: 255, red: 255, green: 255, blue: 255 }); // 用白色清空
这会用你指定的颜色填充整个画布的裁剪区域。效果等同于 drawColor。
完整示例:画一个简单的图形页面
来一个完整的例子,在页面上画一个红色矩形、一个蓝色圆、一条绿色线:
import { RenderNode } from '@kit.ArkUI';
import { common2D, drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context: DrawContext) {
const canvas = context.canvas;
// 画一个红色填充的矩形
const brush = new drawing.Brush();
brush.setColor(255, 255, 0, 0); // 红色
canvas.attachBrush(brush);
canvas.drawRect(20, 20, 200, 120);
canvas.detachBrush();
// 画一个蓝色边框的圆
const pen = new drawing.Pen();
pen.setColor(255, 0, 0, 255); // 蓝色
pen.setStrokeWidth(3);
canvas.attachPen(pen);
canvas.drawCircle(300, 80, 50);
canvas.detachPen();
// 画一条绿色的线
const linePen = new drawing.Pen();
linePen.setColor(255, 0, 200, 0); // 绿色
linePen.setStrokeWidth(5);
canvas.attachPen(linePen);
canvas.drawLine(20, 160, 400, 160);
canvas.detachPen();
}
}
每画一种图形,都重新创建 Brush/Pen、设置颜色、attach、画、detach。这样最清晰,不容易出错。
你可能会问:为什么要不停地 attach/detach?不能设一次一直用吗?可以,但如果你后面要画不同颜色的图形,就得重新设置。attach/detach 的方式更灵活——你可以随时切换不同的 Brush/Pen 组合。
几个注意事项
1. 单线程模型
drawing 模块是单线程的,Canvas 不是线程安全的。如果你在多个线程里同时操作同一个 Canvas,会出问题。所有绘制操作都应该在同一个线程里完成。
2. 单位是物理像素
drawing 模块用的是屏幕物理像素(px),不是 dp。如果你的设备是 2x 密度屏,100px 实际上是 50dp。在不同密度的设备上,图形的大小可能会不一样。你可以用 px2vp 之类的工具函数做转换。
3. 画布自带默认画刷
Canvas 创建后自带一个默认画刷:黑色、开启反走样。如果你没有 attach 任何 Brush/Pen,画出来的图形就是黑色填充的。
4. 顺序很重要
先画的在下面,后画的在上面。如果你先画了一个大矩形,再画一个小圆,小圆会盖在大矩形上面。
小结
Canvas + Brush + Pen 是 HarmonyOS 2D 绘制的基础三件套:
- Canvas:画布,承载所有绘制操作。
- Brush:画刷,控制填充颜色和透明度。
- Pen:画笔,控制描边颜色、线宽、线帽、连接样式。
用法就是:创建 → 设置样式 → attach 到 Canvas → 画图 → detach。
下一篇我们深入讲 Brush 和 Pen 的更多玩法,比如渐变、阴影、自定义颜色矩阵。
更多推荐



所有评论(0)