使用Drawing实现图形绘制与显示
场景介绍
@ohos.graphics.drawing模块提供了基本的绘制能力,如绘制矩形、圆形、点、直线、自定义Path、字体等等。
接口说明
@ohos.graphics.drawing常用接口如下表所示,详细的接口说明请参考@ohos.graphics.drawing。
接口名 | 描述 |
---|---|
drawPath(path: Path) : void | 画一个自定义路径。 |
drawRect(rect: common2D.Rect): void | 用于绘制一个矩形,默认使用黑色填充。 |
drawTextBlob(blob: TextBlob, x: number, y: number): void | 用于绘制一段文字。 |
moveTo(x: number, y: number) : void | 设置自定义路径的起始点位置。 |
lineTo(x: number, y: number) : void | 添加一条到目标点的线段。 |
close(): void | 闭合路径,会添加一条到路径起点位置的线段。 |
setAntiAlias(aa: boolean) : void | 用于设置画笔是否开启反走样。开启后,可以使得图形的边缘在显示时更平滑。 |
setColor(color: common2D.Color) : void | 用于设置画笔和画刷的颜色。 |
setStrokeWidth(width: number) : void | 用于设置画笔的线宽。 |
attachPen(pen: Pen): void | 绑定画笔给画布,画布将使用画笔的样式和颜色去绘制图形形状的轮廓。 |
attachBrush(brush: Brush): void | 绑定画刷给画布,画布将使用画刷的样式和颜色去绘制图形形状,并在其内部进行填充。 |
开发步骤
使用Drawing进行图形绘制与显示时,需要使用@ohos.graphics.drawing模块的画布画笔绘制基本的2D图形和文字,调用绘制和显示的逻辑,最终在应用上显示图形和文字。
本文以实现2D图形和文字的绘制与显示为例,给出具体的开发指导。
添加开发依赖
添加动态链接库
CMakeLists.txt中添加以下lib。
libace_ndk.z.so
libnative_window.so
libnative_drawing.so
依赖文件
import { NodeController, FrameNode, RenderNode, DrawContext } from "@ohos.arkui.node"
import { UIContext } from '@ohos.arkui.UIContext'
import drawing from "@ohos.graphics.drawing"
import image from '@ohos.multimedia.image'
import common2D from '@ohos.graphics.common2D'
接下来介绍如何使用Drawing接口进行内容绘制。
绘制2D图形
以下步骤描述了如何使用@ohos.graphics.drawing模块的画布画笔绘制基本的2D图形和文字:
-
创建RenderNode子类。创建
RenderNode
子类MyRenderNode
,并在其中定义绘图函数。RenderNode
中包含树结构的操作,以及对绘制属性的操作。// 创建一个MyRenderNode类,并构建Path形状。 class MyRenderNode extends RenderNode { async draw(context: DrawContext) { // ... } }
-
构建Path形状。使用path的
moveTo
,lineTo
和close
接口构建五角星形状的Path。const canvas = context.canvas let height_ = 1200 let width_ = 600 let len = height_ / 4 let aX = width_ / 2 let aY = height_ / 4 let dX = aX - len * Math.sin(18.0) let dY = aY + len * Math.cos(18.0) let cX = aX + len * Math.sin(18.0) let cY = dY let bX = aX + (len / 2.0) let bY = aY + Math.sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0)) let eX = aX - (len / 2.0) let eY = bY; // 创建一个path对象,然后使用接口连接成一个五角星形状 let path = new drawing.Path() // 指定path的起始位置 path.moveTo(aX, aY) // 用直线连接到目标点 path.lineTo(bX, bY) path.lineTo(cX, cY) path.lineTo(dX, dY) path.lineTo(eX, eY) // 闭合形状,path绘制完毕 path.close()
-
设置画笔和画刷样式。使用
Pen
接口创建一个画笔实例pen,并设置抗锯齿、颜色、线宽等属性,画笔用于形状边框线的绘制。使用Brush
接口创建一个画刷实例brush,并设置填充颜色,画刷用于形状内部的填充。使用canvas中的attachPen
和attachBrush
接口将画笔画刷的实例设置到画布实例中。// 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制 let pen = new drawing.Pen() pen.setAntiAlias(true) let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 } pen.setColor(pen_color) pen.setStrokeWidth(10.0) // 将Pen画笔设置到canvas中 canvas.attachPen(pen) // 创建一个画刷Brush对象,Brush对象用于形状的填充 let brush = new drawing.Brush() let brush_color : common2D.Color = { alpha: 0xFF, red: 0x00, green: 0xFF, blue: 0x00 } brush.setColor(brush_color) // 将Brush画刷设置到canvas中 canvas.attachBrush(brush)
-
绘制Path形状。使用canvas中的
drawPath
接口将五角星绘制到画布上。// 绘制path canvas.drawPath(path)
-
创建MyRenderNode对象。以上1到4步构建出了MyRenderNode类并在其中定义了绘图的主要函数,接下来创建一个MyRenderNode对象,并设置它的像素格式。
// 创建一个MyRenderNode对象 const newNode = new MyRenderNode() // 定义newNode的像素格式 newNode.frame = { x: 100, y: 100, width: 200, height: 800 } newNode.pivot = { x: 0.2, y: 0.8 } newNode.scale = { x: 1, y: 1 }
-
绘制矩形。使用canvas中的
drawRect
接口绘制矩形。class RectRenderNode extends RenderNode { async draw(context: DrawContext) { const canvas = context.canvas const pen = new drawing.Pen() pen.setStrokeWidth(5) pen.setColor({alpha: 255, red: 255, green: 0, blue: 0}) canvas.attachPen(pen) canvas.drawRect({ left : 200, right : 500, top : 300, bottom : 900}) } } // 创建一个RectRenderNode对象 const rectNode = new RectRenderNode() // 定义rectNode的像素格式 rectNode.frame = { x: 90, y: 100, width: 200, height: 800 } rectNode.pivot = { x: 0.2, y: 0.8 } rectNode.scale = { x: 1, y: 1 }
-
绘制文字。使用canvas中的
drawTextBlob
接口绘制文字。class TextRenderNode extends RenderNode { async draw(context: DrawContext) { const canvas = context.canvas const brush = new drawing.Brush() brush.setColor({alpha: 255, red: 255, green: 0, blue: 0}) const font = new drawing.Font() font.setSize(100) const textBlob = drawing.TextBlob.makeFromString("Hello World", font, drawing.TextEncoding.TEXT_ENCODING_UTF8) canvas.attachBrush(brush) canvas.drawTextBlob(textBlob, 90, 500) } } // 创建一个TextRenderNode对象 const textNode = new TextRenderNode() // 定义textNode的像素格式 textNode.frame = { x: 90, y: 100, width: 200, height: 800 } textNode.pivot = { x: 0.2, y: 0.8 } textNode.scale = { x: 1, y: 1 }
-
创建NodeController子类。创建
NodeController
的子类MyNodeController
,并在其中定义创建FrameNode
的函数。NodeController
定义了节点容器的控制器,控制着容器里在生命周期中的节点。FrameNode
定义了节点的基本类型,并包含一个RenderNode
。class MyNodeController extends NodeController { private rootNode: FrameNode | null = null; makeNode(uiContext: UIContext): FrameNode { this.rootNode = new FrameNode(uiContext) if (this.rootNode == null) { return this.rootNode } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.frame = { x: 0, y: 0, width: 10, height: 500 } renderNode.pivot = { x: 50, y: 50 } } return this.rootNode } }
-
创建添加节点的接口。在第8步中创建的
MyNodeController
类中创建添加RenderNode
的接口。addNode(node: RenderNode): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.appendChild(node) } }
-
创建删除节点的接口。在第8步中创建的
MyNodeController
类中创建删除RenderNode
的接口。clearNodes(): void { if (this.rootNode == null) { return } const renderNode = this.rootNode.getRenderNode() if (renderNode != null) { renderNode.clearChildren() } }
-
绘制图形和文字。创建
MyNodeController
实例并将其存入NodeContainer
,添加button控件供用户点击,并调用已定义的接口。@Entry @Component struct RenderTest { private myNodeController: MyNodeController = new MyNodeController() build() { Column() { Row() { NodeContainer(this.myNodeController) .height('100%') Button("Draw Path") .margin({ bottom: 200, right: 12 }) .onClick(() => { this.myNodeController.clearNodes() this.myNodeController.addNode(newNode) }) Button("Draw Rect") .margin({ bottom: 200, right: 12 }) .onClick(() => { this.myNodeController.clearNodes() this.myNodeController.addNode(rectNode) }) Button("Draw Text") .margin({ bottom: 200, right: 12 }) .onClick(() => { this.myNodeController.clearNodes() this.myNodeController.addNode(textNode) }) } .width('100%') .justifyContent(FlexAlign.Center) .shadow(ShadowStyle.OUTER_DEFAULT_SM) .alignItems(VerticalAlign.Bottom) .layoutWeight(1) } } }
-
绘制与显示的效果图如下:
主页 | 绘制五角星 | 绘制矩形 | 绘制文字 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |