鸿蒙中 自定义绘制:画布获取与显示(二)
一、CanvasCanvas即画布提供绘制基本图形的能力用于在屏幕上绘制图形和处理图形。可以通过Canvas实现自定义的绘图效果增强应用的用户体验。两种获取Canvas的方式方式说明上屏方式可直接显示的Canvas画布调用绘制接口后无需额外操作即可完成上屏显示自动离屏Canvas画布需要依靠已有的显示手段来显示绘制结果手动二、获取可直接显示的Canvas画布通过RenderNode获取可直接上屏显示的Canvas画布。2.1 导入依赖模块import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from kit.ArkUI; import { drawing } from kit.ArkGraphics2D;2.2 自定义RenderNode自定义RenderNode重写draw()函数获取Canvas进行自定义绘制。class MyRenderNodeDirectDisplay extends RenderNode { async draw(context: DrawContext) { const canvas context.canvas; if (canvas null) { console.error(Canvas is null.); return; } // 自定义绘制操作绘制一个红色矩形 const brush new drawing.Brush(); if (brush null) { console.error(Brush is null.); return; } else { brush.setColor({ red: 255, blue: 0, green: 0, alpha: 255 }); canvas.attachBrush(brush); canvas.drawRect({ left: 0, right: 300, top: 0, bottom: 300 }); } } }2.3 自定义NodeController自定义NodeController将自定义RenderNode添加到节点树中。class MyNodeControllerDirectDisplay extends NodeController { private rootNode: FrameNode | null null; private myRenderNode new MyRenderNodeDirectDisplay(); makeNode(uiContext: UIContext): FrameNode { this.rootNode new FrameNode(uiContext); if (this.rootNode null) { return this.rootNode; } const renderNode this.rootNode.getRenderNode(); if (renderNode ! null) { this.myRenderNode.backgroundColor 0xffffffff; this.myRenderNode.frame { x: 0, y: 0, width: 4800, height: 4800 }; this.myRenderNode.pivot { x: 0.2, y: 0.8 }; this.myRenderNode.scale { x: 1, y: 1 }; renderNode.appendChild(this.myRenderNode); renderNode.clipToFrame true; } return this.rootNode; } }2.4 显示NodeControllerEntry Component struct RenderTest { myNodeController_1 new MyNodeControllerDirectDisplay(); build() { Row() { Column() { Column() { Text(直接上屏显示画布) // 直接上屏显示画布 NodeContainer(this.myNodeController_1) .width(100%) .height(40%) } } } } }三、离屏Canvas画布的获取与显示离屏Canvas画布的获取与显示需要先创建PixelMap利用PixelMap构造离屏Canvas绘制后将结果交给RenderNode上屏。3.1 导入依赖模块import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from kit.ArkUI; import { image } from kit.ImageKit; import { taskpool } from kit.ArkTS; import { drawing } from kit.ArkGraphics2D;3.2 自定义RenderNodeexport class MyRenderNodeIndirectDisplay extends RenderNode { private pixelMap: image.PixelMap | null null; setPixelMap(pixelMap: image.PixelMap) { this.pixelMap pixelMap; } async draw(context: DrawContext) { const canvas context.canvas; if (this.pixelMap ! null) { // 利用PixelMap构造离屏Canvas const canvas_ new drawing.Canvas(this.pixelMap); // 离屏绘制绘制一个蓝色矩形 const brush new drawing.Brush(); brush.setColor({ alpha: 255, red: 0, green: 0, blue: 255 }); canvas_.attachBrush(brush); canvas_.drawRect({ left: 150, right: 575, top: 0, bottom: 600 }); // 将离屏Canvas的绘制结果交给RenderNode canvas.drawImage(this.pixelMap, 0, 0); } } }3.3 创建PixelMap的异步任务Concurrent async function createPixelMapAsync() { // 4000000为需要创建的像素buffer大小取值为height × width × 4 const color: ArrayBuffer new ArrayBuffer(4000000); let opts: image.InitializationOptions { editable: true, pixelFormat: 3, size: { height: 1000, width: 1000 } }; const pixel await image.createPixelMap(color, opts); return pixel; }3.4 自定义NodeControllerexport class MyNodeControllerIndirectDisplay extends NodeController { private rootNode: FrameNode | null null; private myRenderNode new MyRenderNodeIndirectDisplay(); // 在aboutToAppear中创建PixelMap aboutToAppear(): void { let task new taskpool.Task(createPixelMapAsync); taskpool.execute(task).then((pixel: Object) { this.myRenderNode.setPixelMap(pixel as image.PixelMap); this.myRenderNode.invalidate(); }); } makeNode(uiContext: UIContext): FrameNode { this.rootNode new FrameNode(uiContext); if (this.rootNode null) { return this.rootNode; } const renderNode this.rootNode.getRenderNode(); if (renderNode ! null) { this.myRenderNode.backgroundColor 0xffffffff; this.myRenderNode.frame { x: 0, y: 0, width: 4800, height: 4800 }; this.myRenderNode.pivot { x: 0.2, y: 0.8 }; this.myRenderNode.scale { x: 1, y: 1 }; renderNode.appendChild(this.myRenderNode); renderNode.clipToFrame true; } return this.rootNode; } }3.5 显示NodeControllerEntry Component struct RenderTest { myNodeController_2 new MyNodeControllerIndirectDisplay(); build() { Row() { Column() { Column() { Text(离屏画布) // 离屏画布 NodeContainer(this.myNodeController_2) .width(100%) .height(40%) .margin({ top: 20 }) } } } } }四、两种方式对比对比项直接显示Canvas离屏Canvas获取方式通过RenderNode获取context.canvas通过PixelMap构造drawing.Canvas上屏方式自动上屏需手动调用canvas.drawImage()适用场景简单直接绘制需要离线处理后再显示复杂度低较高开发流程直接显示方式自定义RenderNode → 重写draw()获取Canvas → 绘制 → NodeContainer显示离屏显示方式创建PixelMap → 构造离屏Canvas → 绘制 → canvas.drawImage()上屏 → NodeContainer显示ArkTS中可通过RenderNode获取可直接显示的Canvas画布自动上屏或通过PixelMap构造离屏Canvas绘制后手动上屏两种方式都需自定义RenderNode和NodeController并通过NodeContainer显示。