【愚公系列】2023年12月 HarmonyOS教学课程 029-ArkUI组件(Canvas)
🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2023年华为云十佳博主,2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
🚀一、Canvas
Canvas组件是一种图形渲染组件,它提供了一个画布(canvas),开发者可以在上面绘制各种图形、文本等。Canvas组件通常用于创建游戏、数据可视化等需要动态绘制图形的应用程序。
Canvas组件提供了多个API,开发者可以使用这些API进行绘制操作。常用的API包括绘制矩形、圆形、线条、文字等。开发者可以设置画布的大小、背景色、绘制的颜色、线条的宽度等属性。
在Canvas组件中,开发者可以监听鼠标事件(如点击、移动等)和键盘事件,以便根据用户的交互来实现相应的操作。
Canvas组件的使用通常需要一定的编程知识和技巧,开发者需要了解如何使用API进行绘图操作,以及如何处理用户的交互事件。
🔎1.使用画布组件绘制自定义图形
🦋1.1 直接绘制
Canvas直接绘制图形的原理是通过Canvas API调用一系列绘制方法来在Canvas元素上绘制图形和图像。Canvas元素本身是一个空的矩形区域,通过获取Canvas的上下文(context),可以使用上下文提供的绘制方法来进行绘制。
@Entry
@Component
struct CanvasExample1 {
//用来配置CanvasRenderingContext2D对象的参数,包括是否开启抗锯齿,true表明开启抗锯齿。
private settings: RenderingContextSettings = new RenderingContextSettings(true)
//用来创建CanvasRenderingContext2D对象,通过在canvas中调用CanvasRenderingContext2D对象来绘制。
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
//在canvas中调用CanvasRenderingContext2D对象。
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() => {
//可以在这里绘制内容。
this.context.strokeRect(50, 50, 200, 150);
})
}
.width('100%')
.height('100%')
}
}
🦋1.2 离屏绘制
离屏绘制(offscreen rendering)是指将渲染结果绘制到与屏幕不直接相关的缓冲区中进行处理。传统的渲染方式是直接将图像渲染到屏幕上,而离屏绘制则是在一个特定的缓冲区中进行渲染,然后再将渲染结果显示到屏幕上。
离屏绘制的主要作用是实现一些特殊效果,比如阴影、模糊、遮罩等。这些效果通常需要在渲染过程中进行多次操作,直接在屏幕上渲染会导致效率低下。使用离屏绘制可以在一个独立的缓冲区中进行这些操作,然后再将结果绘制到屏幕上。
离屏绘制可以通过一些图形库或引擎来实现,例如OpenGL、DirectX等。在移动设备上,离屏绘制通常使用Frame Buffer来实现。开发者可以通过指定一个离屏渲染的目标缓冲区,然后在这个缓冲区中进行渲染操作,最后再将结果绘制到屏幕上。
离屏绘制虽然可以实现一些特殊效果,但由于需要额外的资源和计算开销,使用不当会导致性能问题。因此,在使用离屏绘制时应该注意减少不必要的操作和资源消耗,以提高性能和用户体验。
@Entry
@Component
struct CanvasExample2 {
//用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
//用来创建OffscreenCanvasRenderingContext2D对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
//可以在这里绘制内容
this.offContext.strokeRect(50, 50, 200, 150);
//将离屏绘值渲染的图像在普通画布上显示
let image = this.offContext.transferToImageBitmap();
this.context.transferFromImageBitmap(image);
})
}
.width('100%')
.height('100%')
}
}
在Canvas上加载Lottie动画时,需要先按照如下方式下载Lottie,具体使用:https://ohpm.openharmony.cn/#/cn/detail/@ohos/lottie
🔎2.初始化画布组件
在HarmonyOS中,Canvas类是用于绘制图形的核心类。Canvas类提供了onReady方法,用于在Canvas准备好进行绘制之后的回调操作。
当Canvas准备好进行绘制时,会调用onReady方法。开发者可以重写onReady方法,实现一些绘制前的准备工作,例如设置画笔颜色、绘制区域等。
要使用Canvas的onReady方法,需要创建一个Canvas实例,然后通过实例调用onReady方法。
@Entry
@Component
struct CanvasExample2 {
//用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
//用来创建OffscreenCanvasRenderingContext2D对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() => {
this.context.fillStyle = '#0097D4';
this.context.fillRect(50, 50, 100, 100);
})
}
.width('100%')
.height('100%')
}
}
🔎3.画布组件绘制方式
Canvas类支持使用Path2D对象来绘制复杂的路径图形。
Path2D是一个可重用的路径对象,用于描述二维空间中的路径。开发者可以使用Path2D对象来定义路径的轮廓,并在Canvas上绘制出来。
@Entry
@Component
struct CanvasExample2 {
//用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
//用来创建OffscreenCanvasRenderingContext2D对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
this.context.beginPath();
this.context.moveTo(50, 50);
this.context.lineTo(280, 160);
this.context.stroke();
})
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
let region = new Path2D();
region.arc(100, 75, 50, 0, 6.28);
this.context.stroke(region);
})
}
.width('100%')
.height('100%')
}
}
🔎4.画布组件常用方法
方法/属性 | 说明 |
---|---|
fill() | 对封闭路径进行填充 |
clip() | 设置当前路径为剪切路径 |
stroke() | 进行边框绘制操作 |
fillStyle | 指定绘制的填充色 |
globalAlpha | 设置透明度 |
strokeStyle | 设置描边的颜色 |
Font | 设置字体样式 |
textAlign | 设置文本对齐方式 |
textBaseline | 设置基线对齐方式 |
measureText() | 测量文本的宽度 |
drawImage() | 绘制图片 |
createImageData() | 创建一个新的、空白的ImageData对象 |
getImageData() | 获取指定区域的图像数据 |
putImageData() | 将像素数据放回画布上的指定位置 |
createLinearGradient() | 创建线性渐变 |
createRadialGradient() | 创建径向渐变 |
createPattern() | 创建图案 |
drawFocusIfNeeded() | 如果元素具有焦点,则绘制它 |
addHitRegion() | 添加点击区域 |
removeHitRegion() | 移除点击区域 |
isPointInPath() | 判断指定点是否在路径中 |
clearRect() | 清除指定矩形区域 |
save() | 保存当前绘图状态 |
restore() | 恢复上一个保存的绘图状态 |
scale() | 缩放当前绘图 |
rotate() | 旋转当前绘图 |
translate() | 平移当前绘图 |
transform() | 通过矩阵变换,应用缩放、旋转、平移、扭曲等变换 |
setTransform() | 通过矩阵变换,应用缩放、旋转、平移等变换 |
createOffscreenCanvas() | 创建离屏画布 |
getContext() | 获取绘图上下文对象 |
draw() | 将离屏画布上的绘制内容绘制到主画布上 |
clear() | 清除离屏画布 |
closePath() | 关闭当前路径 |
moveTo() | 将绘图游标移动到指定的坐标位置 |
lineTo() | 添加一条直线连接到指定的坐标点 |
arc() | 以给定的中心点和半径,绘制弧形路径 |
quadraticCurveTo() | 添加二次贝塞尔曲线连接到指定的坐标点 |
bezierCurveTo() | 添加三次贝塞尔曲线连接到指定的坐标点 |
arcTo() | 通过给定的控制点和半径,绘制连接两个切线的圆弧路径 |
rect() | 绘制一个矩形路径 |
isPointInStroke() | 判断指定点是否在路径的描边上 |
strokeRect() | 绘制一个矩形路径的边框 |
fillRect() | 绘制一个填充的矩形路径 |
beginPath() | 开始一个新的路径 |
drawTextOnPath() | 沿着路径绘制文本 |
drawVisible() | 绘制离屏画布的可见区域到主画布上 |
toDataURL() | 将画布内容转为数据URL格式 |
getTransform() | 获取当前绘图的变换矩阵 |
setLineDash() | 设置虚线样式 |
getLineDash() | 获取虚线样式 |
resetTransform() | 重置当前绘图的变换矩阵 |
drawCustomEffect() | 绘制自定义特效 |
drawShadow() | 绘制阴影 |
🦋4.1 基础形状绘制
可以通过arc(绘制弧线路径)、 ellipse(绘制一个椭圆)、rect(创建矩形路径)等接口绘制基础形状
@Entry
@Component
struct CanvasExample2 {
//用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
//用来创建OffscreenCanvasRenderingContext2D对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
//绘制矩形
this.context.beginPath();
this.context.rect(100, 50, 100, 100);
this.context.stroke();
//绘制圆形
this.context.beginPath();
this.context.arc(150, 250, 50, 0, 6.28);
this.context.stroke();
//绘制椭圆
this.context.beginPath();
this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);
this.context.stroke();
})
}
.width('100%')
.height('100%')
}
}
🦋4.2 文本绘制
可以通过fillText(绘制填充类文本)、strokeText(绘制描边类文本)等接口进行文本绘制。
@Entry
@Component
struct CanvasExample2 {
//用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
//用来创建OffscreenCanvasRenderingContext2D对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
//绘制填充类文本
this.context.font = '50px sans-serif';
this.context.fillText("Hello World!", 50, 100);
//绘制描边类文本
this.context.font = '55px sans-serif';
this.context.strokeText("Hello World!", 50, 150);
})
}
.width('100%')
.height('100%')
}
}
🦋4.3 绘制图片和图像像素信息处理
接口 | 描述 |
---|---|
drawImage | 用于绘制图像 |
putImageData | 使用ImageData数据填充新的矩形区域 |
createImageData | 创建新的ImageData对象 |
getPixelMap | 以当前canvas指定区域内的像素创建PixelMap对象 |
getImageData | 以当前canvas指定区域内的像素创建ImageData对象 |
@Entry
@Component
struct GetImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private img:ImageBitmap = new ImageBitmap("1702344909275.jpg")
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
// 使用drawImage接口将图片画在(0,0)为起点,宽高130的区域
this.offContext.drawImage(this.img,0,0,130,130);
// 使用getImageData接口,获得canvas组件区域中,(50,50)为起点,宽高130范围内的绘制内容
let imagedata = this.offContext.getImageData(50,50,130,130);
// 使用putImageData接口将得到的ImageData画在起点为(150, 150)的区域中
this.offContext.putImageData(imagedata,150,150);
// 将离屏绘制的内容画到canvas组件上
let image = this.offContext.transferToImageBitmap();
this.context.transferFromImageBitmap(image);
})
}
.width('100%')
.height('100%')
}
}
🦋4.4 其他方法
Canvas中还提供其他类型的方法。渐变(CanvasGradient对象)相关的方法:createLinearGradient(创建一个线性渐变色)、createRadialGradient(创建一个径向渐变色)等。
Canvas的createRadialGradient方法用于创建一个径向渐变色。
语法:
createRadialGradient(x0, y0, r0, x1, y1, r1)
参数说明:
- x0:渐变的起始圆的x坐标
- y0:渐变的起始圆的y坐标
- r0:渐变的起始圆的半径
- x1:渐变的结束圆的x坐标
- y1:渐变的结束圆的y坐标
- r1:渐变的结束圆的半径
@Entry
@Component
struct GetImageData {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
private img:ImageBitmap = new ImageBitmap("1702344909275.jpg")
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
//创建一个径向渐变色的CanvasGradient对象
let grad = this.context.createRadialGradient(200,200,50, 200,200,200)
//为CanvasGradient对象设置渐变断点值,包括偏移和颜色
grad.addColorStop(0.0, '#E87361');
grad.addColorStop(0.5, '#FFFFF0');
grad.addColorStop(1.0, '#BDDB69');
//用CanvasGradient对象填充矩形
this.context.fillStyle = grad;
this.context.fillRect(0, 0, 400, 400);
})
}
.width('100%')
.height('100%')
}
}
🔎5.场景示例
🦋5.1 规则基础形状绘制
@Entry
@Component
struct ClearRect {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
// 设定填充样式,填充颜色设为蓝色
this.context.fillStyle = '#0097D4';
// 以(50, 50)为左上顶点,画一个宽高200的矩形
this.context.fillRect(50,50,200,200);
// 以(70, 70)为左上顶点,清除宽150高100的区域
this.context.clearRect(70,70,150,100);
})
}
.width('100%')
.height('100%')
}
}
🦋5.2 不规则图形绘制
@Entry
@Component
struct Path2d {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
build() {
Row() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() =>{
// 使用Path2D的接口构造一个五边形
let path = new Path2D();
path.moveTo(150, 50);
path.lineTo(50, 150);
path.lineTo(100, 250);
path.lineTo(200, 250);
path.lineTo(250, 150);
path.closePath();
// 设定填充色为蓝色
this.context.fillStyle = '#0097D4';
// 使用填充的方式,将Path2D描述的五边形绘制在canvas组件内部
this.context.fill(path);
})
}
.width('100%')
}
.height('100%')
}
}
🚀感谢:给读者的一封信
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。
如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。
再次感谢您的阅读和支持!
最诚挚的问候, “愚公搬代码”
- 点赞
- 收藏
- 关注作者
评论(0)