Canvas提供画布组件,用于自定义绘制图形,开发者使用CanvasRenderingContext2D对象在Canvas组件上进行绘制,绘制对象可以是基础形状、文本、图片等。
1. 基本使用:
Canvas(context: CanvasRenderingContext2D | DrawingRenderingContext)
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| context | CanvasRenderingContext2D |DrawingRenderingContext | 是 | 绘画上下文 |
注: API12以上,可添加imageAIOptions参数,给组件设置AI分析选项,通过此项可配置分析类型或绑定一个分析控制器。
使用步骤:
- 放置Canvas组件-设置宽和高
- 初始化画笔对象 CanvasRenderingContext2D,将画笔对象作为构造参数传递给Canvas组件
- 可以在Canvas的onReady事件中进行动态绘制
简单示例:
@Entry
@Component
struct CanvasDemo {
/* 准备绘制上下文 */
ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D()
build() {
Canvas(this.ctx)
.width('100%')
.aspectRatio(1)
.backgroundColor('#f1f1f1')
.onReady(() => {
//绘制矩形
this.ctx.beginPath();
this.ctx.rect(100, 50, 100, 100);
this.ctx.stroke();
//绘制圆形
this.ctx.beginPath();
this.ctx.arc(150, 250, 50, 0, 6.28);
this.ctx.stroke();
//绘制椭圆
this.ctx.beginPath();
this.ctx.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);
this.ctx.stroke();
})
}
}
上述代码中用到了onReady事件,是Canvas组件初始化完成时或者Canvas组件发生大小变化时的事件回调,当该事件被触发时画布被清空。当Canvas组件仅发生位置变化时,只触发onAreaChange事件、不触发onReady事件。onAreaChange事件在onReady事件后触发。
2. 绘制上下文
可以用来绘制文本、图形,处理像素等,是Canvas组件的核心。常用接口有fill(对封闭路径进行填充)、clip(设置当前路径为剪切路径)、stroke(进行边框绘制操作)等等,同时提供了fillStyle(指定绘制的填充色)、globalAlpha(设置透明度)与strokeStyle(设置描边的颜色)等属性修改绘制内容的样式。将通过以下几个方面简单介绍画布组件常见使用方法:
基础形状绘制。 可以通过arc(绘制弧线路径)、 ellipse(绘制一个椭圆)、rect(创建矩形路径)等接口绘制基础形状。
2.1. 常用属性
| 属性 | 类型 | 说明 |
|---|---|---|
| fillStyle | string |number |CanvasGradient | 指定绘制的填充色(可设置渐变色) |
| lineWidth | number | 设置绘制线条的宽度,不支持0和负数 |
| strokeStyle | string |number |CanvasGradient | 设置线条的颜色(可设置渐变色) |
| font | string | 设置文本绘制中的字体样式。 |
| textAlign | CanvasTextAlign | 设置文本绘制中的文本对齐方式 |
| globalAlpha | number | 设置透明度 |
| height | number | 组件高度 |
| width | number | 组件宽度 |
| direction | CanvasDirection | 用于设置绘制文字时使用的文字方向。 |
说明: fillStyle、strokeStyle的参数类型:
- 类型为string时,表示设置线条使用的颜色,默认值:'black'
- 类型为number时,表示设置线条使用的颜色。默认值:'#000000'
- 类型为CanvasGradient时,表示渐变对象,使用createLinearGradient方法创建
/* 渐变色示例 */
let grad = this.context.createLinearGradient(50,0, 300,100) // 线性渐变色
let grad = this.context.createRadialGradient(200,200,50, 200,200,200) // 径向渐变色
grad.addColorStop(0.0, '#ff0000')
grad.addColorStop(0.5, '#ffffff')
grad.addColorStop(1.0, '#00ff00')
font的语法格式:ctx.font='font-style font-weight font-size font-family'
2.2. 常用方法:
fillRect(x, y, width, height):绘制一个填充矩形。strokeRect(x, y, width, height):绘制一个只有边框的矩形。clearRect(x, y, width, height):清除指定矩形区域内的内容。fillText(text, x, y, maxWidth):在画布上绘制填充文本。strokeText(text, x, y, maxWidth):在画布上绘制描边文本。beginPath():开始一条新的路径。closePath():关闭当前路径。moveTo(x, y):将路径移动到画布上的指定点。lineTo(x, y):在当前位置和指定点之间创建直线。arc(x, y, radius, startAngle, endAngle, anticlockwise):绘制一个弧形路径。ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise):绘制椭圆rect(x, y, width, height):创建一个矩形路径。fill(path):对指定路径进行填充。stroke(path):对指定路径进行描边。drawImage(image, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight):在画布上绘制图像。toDataURL(type?, quality?): 生成一个包含图片展示的URL
-
- type:可选参数,用于指定图像格式,默认格式为image/png
- quality: 图片质量可以从0到1的区间内选择图片的质量,默认值0.92
reset():重置画板为默认状态restore():对保存的绘图上下文进行恢复
其他详情方法请参考:CanvasRenderingContext2D方法
3. 配合Touch事件签字
关键代码:
.onTouch((event: TouchEvent) => {
let x = event.touches[0].x
let y = event.touches[0].y
// 手指按下,开始绘画
if (event.type === TouchType.Down) {
this.ctx.beginPath()
this.ctx.moveTo(x, y)
// 手指移动,画笔移动
} else if (event.type === TouchType.Move) {
this.ctx.lineTo(x, y)
this.ctx.stroke()
// 手指抬起,结束绘画
} else if (event.type === TouchType.Up) {
this.ctx.closePath()
}
其他功能:
- 保存图片: toDataURL(),返回包含图片展示的URL
Button('生成图片')
.onClick(() => {
this.canvasImage = this.ctx.toDataURL("image/png", 0.92)
})
- 清空画板: reset()
Button('清空画板')
.onClick(() => {
this.ctx.reset()
})
完整代码:
@Entry
@Component
struct CanvasDemo {
ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D()
@State canvasImage: string = ''
build() {
Column({ space: 20 }) {
Canvas(this.ctx)
.width('100%')
.aspectRatio(1)
.backgroundColor('#f1f1f1')
.onReady(() => {
// 设置画笔的颜色和宽度
this.ctx.strokeStyle = '#000'
this.ctx.lineWidth = 2
})
.onTouch((event: TouchEvent) => {
let x = event.touches[0].x
let y = event.touches[0].y
// 手指按下,开始绘画
if (event.type === TouchType.Down) {
this.ctx.beginPath()
this.ctx.moveTo(x, y)
} else if (event.type === TouchType.Move) {
this.ctx.lineTo(x, y)
this.ctx.stroke()
} else if (event.type === TouchType.Up) {
this.ctx.closePath()
}
})
Row({ space: 20 }) {
Button('清空画板')
.onClick(() => {
this.ctx.reset()
})
Button('生成图片')
.onClick(() => {
this.canvasImage = this.ctx.toDataURL("image/png", 0.92)
})
}
if (this.canvasImage) {
Image(this.canvasImage)
.width(200)
.aspectRatio(1)
.backgroundColor('#fff')
}
}
.padding(10)
.width('100%')
.height('100%')
.backgroundColor(Color.Pink)
}
}