HarmonyOS Next 自定义图形Canvas实践

HarmonyOS Next中使用Canvas提供画布组件,用于自定义绘制图形,我们可以使用CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象在Canvas组件上进行绘制,绘制对象可以是基础形状、文本、图片等。

HarmonyOS Next 提供了以下三种形式在画布绘制自定义图形:

  1. 使用CanvasRenderingContext2D对象在Canvas画布上绘制。
  2. 离屏绘制是指将需要绘制的内容先绘制在缓存区,再将其转换成图片,一次性绘制到Canvas上,加快了绘制速度。
  3. 在Canvas上加载Lottie动画。
Canvas绘制使用步骤

首先我们需要构建RenderingContextSettings对象,然后使用RenderingContextSettings对象对象构建CanvasRenderingContext2D,因为Canvas构造函数中需要传入CanvasRenderingContext2D对象。
下面实现最简单的一个示例:

private settings: RenderingContextSettings = new RenderingContextSettings(true)  
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)  
build() {  
  RelativeContainer() {  
    Canvas(this.context)  
      .width('100%')  
      .height('100%')  
      .backgroundColor('#660099')  
  }  
}

在这里插入图片描述

这里只是简单实现一个背景色,这里面setting用来配置CanvasRenderingContext2D对象的参数,包括是否开启抗锯齿,true表明开启抗锯齿。接下来我们就可以使用CanvasRenderingContext2D操作Canvas了。要操作Canvas必须要等待onReady回调后才可以执行,onReady(event: () => void)是Canvas组件初始化完成时的事件回调,调用该事件后,可获取Canvas组件的确定宽高,进一步使用CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象调用相关API进行图形绘制。

离屏渲染介绍

离屏绘制是指将需要绘制的内容先绘制在缓存区,再将其转换成图片,一次性绘制到Canvas上,加快了绘制速度。过程为:

  1. 通过transferToImageBitmap方法将离屏画布最近渲染的图像创建为一个ImageBitmap对象。
  2. 通过CanvasRenderingContext2D对象的transferFromImageBitmap方法显示给定的ImageBitmap对象。
    在画布组件中,通过CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象在Canvas组件上进行绘制时调用的接口相同。
    下面是一个离屏渲染的示例:
@Entry  
@Component  
struct Index {  
  private settings: RenderingContextSettings = new RenderingContextSettings(true)  
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)  
  private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)  
  
  build() {  
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {  
      Canvas(this.context)  
        .width('100%')  
        .height('100%')  
        .backgroundColor('#5F3CE2')  
        .onReady(() => {  
          let offContext = this.offCanvas.getContext("2d", this.settings)  
          //可以在这里绘制内容  
          offContext.strokeRect(20, 20, 100, 100);  
          //将离屏绘值渲染的图像在普通画布上显示  
          let image = this.offCanvas.transferToImageBitmap();  
          this.context.transferFromImageBitmap(image);  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}
  1. 首先创建setting对象,用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿。
  2. 接下来创建OffscreenCanvas对象,width为离屏画布的宽度,height为离屏画布的高度。通过在canvas中调用OffscreenCanvasRenderingContext2D对象来绘制。
  3. 在onReady中通过let offContext = this.offCanvas.getContext("2d", this.settings)获取离屏上下文
  4. 在离屏画布中绘制矩形
  5. 通过this.offCanvas.transferToImageBitmap()将离屏绘值渲染的图像在普通画布上显示
各种形状绘制
绘制线条

通过beginPath、moveTo、lineTo来实现线条绘制。

@Entry  
@Component  
struct Index {  
  //用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿  
  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('#cbbbf2')  
        .onReady(() => {  
          this.context.beginPath();  
          this.context.moveTo(150, 50);  
          this.context.lineTo(200, 150);  
          this.context.stroke();  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}

在这里插入图片描述

绘制矩形

fillRect绘制实心矩形,strokeRect绘制空心矩形,下面以实心矩形为例:

@Entry  
@Component  
struct Index {  
  //用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿  
  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('#cbbbf2')  
        .onReady(() => {  
          this.context.fillStyle = '#0097D4';  
          this.context.fillRect(50, 50, 100, 100);  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}

在这里插入图片描述

绘制圆形

通过arc绘制圆形:

@Entry  
@Component  
struct Index {  
  //用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿  
  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('#cbbbf2')  
        .onReady(() => {  
          let region = new Path2D();  
          region.arc(100, 75, 50, 0, 6.28);  
          this.context.stroke(region);  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}
绘制椭圆

ellipse可以用来绘制椭圆:

@Entry  
@Component  
struct Index {  
  //用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿  
  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('#cbbbf2')  
        .onReady(() => {  
          this.context.beginPath();  
          this.context.ellipse(150, 150, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);  
          this.context.stroke();  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}

在这里插入图片描述

文本绘制

可以通过fillText(文本填充)、strokeText(文本描边)等接口进行文本绘制,示例中设置了font为50像素高加粗的"sans-serif"字体,然后调用fillText方法在(50, 100)处绘制文本"Hello World!",设置strokeStyle为红色,lineWidth为2,font为50像素高加粗的"sans-serif"字体,然后调用strokeText方法在(50, 150)处绘制文本"Hello World!"的轮廓。

@Entry  
@Component  
struct Index {  
  //用来配置CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象的参数,包括是否开启抗锯齿。true表明开启抗锯齿  
  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('#cbbbf2')  
        .onReady(() => {  
          // 文本填充  
          this.context.font = '50px bolder sans-serif';  
          this.context.fillText("HarmonyOS!", 50, 100);  
          // 文本描边  
          this.context.strokeStyle = "#ff0000"  
          this.context.lineWidth = 2  
          this.context.font = '50px bolder sans-serif';  
          this.context.strokeText("HarmonyOS", 50, 150);  
        })  
    }  
    .width('100%')  
    .height('100%')  
  }  
}

在这里插入图片描述

其他

此外还提供了绘制图片和图像像素信息处理、绘制渐变(CanvasGradient对象)相关的方法:createLinearGradient(创建一个线性渐变色)、createRadialGradient(创建一个径向渐变色)等。

总结

本文详细介绍了在 HarmonyOS Next 中使用 Canvas 组件进行自定义图形绘制的方法。Canvas 是一个用于绘制图形的画布组件,支持通过 CanvasRenderingContext2DOffscreenCanvasRenderingContext2D 对象绘制基础形状、文本、图片等内容。文章重点讲解了三种绘制方式:直接绘制、离屏绘制(提升效率)以及加载 Lottie 动画。