鸿蒙HarmonyOS实战-ArkUI组件(Canvas)

🚀一、Canvas

Canvas组件是一种图形渲染组件,它提供了一个画布(canvas),开发者可以在上面绘制各种图形、文本等。Canvas组件通常用于创建游戏、数据可视化等需要动态绘制图形的应用程序。

Canvas组件提供了多个API,开发者可以使用这些API进行绘制操作。常用的API包括绘制矩形、圆形、线条、文字等。开发者可以设置画布的大小、背景色、绘制的颜色、线条的宽度等属性。

在Canvas组件中,开发者可以监听鼠标事件(如点击、移动等)和键盘事件,以便根据用户的交互来实现相应的操作。

Canvas组件的使用通常需要一定的编程知识和技巧,开发者需要了解如何使用API进行绘图操作,以及如何处理用户的交互事件。

🔎1.使用画布组件绘制自定义图形

🦋1.1 直接绘制

Canvas直接绘制图形的原理是通过Canvas API调用一系列绘制方法来在Canvas元素上绘制图形和图像。Canvas元素本身是一个空的矩形区域,通过获取Canvas的上下文(context),可以使用上下文提供的绘制方法来进行绘制。

less 复制代码
@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来实现。开发者可以通过指定一个离屏渲染的目标缓冲区,然后在这个缓冲区中进行渲染操作,最后再将结果绘制到屏幕上。

离屏绘制虽然可以实现一些特殊效果,但由于需要额外的资源和计算开销,使用不当会导致性能问题。因此,在使用离屏绘制时应该注意减少不必要的操作和资源消耗,以提高性能和用户体验。

typescript 复制代码
@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,具体使用:ohpm.openharmony.cn/#/cn/detail...

🔎2.初始化画布组件

在HarmonyOS中,Canvas类是用于绘制图形的核心类。Canvas类提供了onReady方法,用于在Canvas准备好进行绘制之后的回调操作。

当Canvas准备好进行绘制时,会调用onReady方法。开发者可以重写onReady方法,实现一些绘制前的准备工作,例如设置画笔颜色、绘制区域等。

要使用Canvas的onReady方法,需要创建一个Canvas实例,然后通过实例调用onReady方法。

typescript 复制代码
@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上绘制出来。

kotlin 复制代码
@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(创建矩形路径)等接口绘制基础形状

kotlin 复制代码
@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(绘制描边类文本)等接口进行文本绘制。

kotlin 复制代码
@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对象
kotlin 复制代码
@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方法用于创建一个径向渐变色。

语法:

scss 复制代码
createRadialGradient(x0, y0, r0, x1, y1, r1)

参数说明:

  • x0:渐变的起始圆的x坐标
  • y0:渐变的起始圆的y坐标
  • r0:渐变的起始圆的半径
  • x1:渐变的结束圆的x坐标
  • y1:渐变的结束圆的y坐标
  • r1:渐变的结束圆的半径
typescript 复制代码
@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 规则基础形状绘制

kotlin 复制代码
@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 不规则图形绘制

scss 复制代码
@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%')
  }
}

🚀写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取最新鸿蒙学习资料,请点击→全套鸿蒙HarmonyOS学习资料
相关推荐
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX3 小时前
Android 分区相关介绍
android
大白要努力!4 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood5 小时前
Perfetto学习大全
android·性能优化·perfetto
SameX7 小时前
HarmonyOS Next 安全生态构建与展望
前端·harmonyos
SameX7 小时前
HarmonyOS Next 打造智能家居安全系统实战
harmonyos
Dnelic-7 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen10 小时前
MTK Android12 user版本MtkLogger
android·framework
Random_index14 小时前
#Uniapp篇:支持纯血鸿蒙&发布&适配&UIUI
uni-app·harmonyos