1# 使用Drawing实现图形绘制与显示 2 3## 场景介绍 4 5@ohos.graphics.drawing模块提供了基本的绘制能力,如绘制矩形、圆形、点、直线、自定义Path、字体等等。 6 7## 接口说明 8 9@ohos.graphics.drawing常用接口如下表所示,详细的接口说明请参考[@ohos.graphics.drawing](../reference/apis-arkgraphics2d/js-apis-graphics-drawing.md)。 10 11| 接口名 | 描述 | 12| -------- | -------- | 13| drawPath(path: Path) : void | 画一个自定义路径。 | 14| drawRect(rect: common2D.Rect): void | 用于绘制一个矩形,默认使用黑色填充。 | 15| drawTextBlob(blob: TextBlob, x: number, y: number): void | 用于绘制一段文字。 | 16| moveTo(x: number, y: number) : void | 设置自定义路径的起始点位置。 | 17| lineTo(x: number, y: number) : void | 添加一条到目标点的线段。 | 18| close(): void | 闭合路径,会添加一条到路径起点位置的线段。 | 19| setAntiAlias(aa: boolean) : void | 用于设置画笔是否开启反走样。开启后,可以使得图形的边缘在显示时更平滑。| 20| setColor(color: common2D.Color) : void | 用于设置画笔和画刷的颜色。| 21| setStrokeWidth(width: number) : void | 用于设置画笔的线宽。| 22| attachPen(pen: Pen): void | 绑定画笔给画布,画布将使用画笔的样式和颜色去绘制图形形状的轮廓。| 23| attachBrush(brush: Brush): void | 绑定画刷给画布,画布将使用画刷的样式和颜色去绘制图形形状,并在其内部进行填充。| 24 25## 开发步骤 26 27使用Drawing进行图形绘制与显示时,需要使用@ohos.graphics.drawing模块的画布画笔绘制基本的2D图形和文字,调用绘制和显示的逻辑,最终在应用上显示图形和文字。 28 29本文以实现2D图形和文字的绘制与显示为例,给出具体的开发指导。 30### 添加开发依赖 31 32**依赖文件** 33```js 34import { FrameNode, NodeController, RenderNode } from '@kit.ArkUI' 35import { common2D, drawing } from '@kit.ArkGraphics2D' 36``` 37 38接下来介绍如何使用Drawing接口进行内容绘制。 39 40### 绘制2D图形 41 42以下步骤描述了如何使用@ohos.graphics.drawing模块的画布画笔绘制基本的2D图形和文字: 43 441. **创建RenderNode子类**。创建`RenderNode`子类`MyRenderNode`,并在其中定义绘图函数。`RenderNode`中包含树结构的操作,以及对绘制属性的操作,其中`draw`方法会在`RenderNode`进行绘制时被调用,更多细节请参考[RenderNode](../reference/apis-arkui/js-apis-arkui-renderNode.md)。 45 46 ```js 47 // 创建一个MyRenderNode类,并构建Path形状。 48 class MyRenderNode extends RenderNode { 49 50 async draw(context: DrawContext) { 51 // ... 52 } 53 } 54 ``` 55 562. **构建Path形状**。使用path的`moveTo`,`lineTo`和`close`接口构建五角星形状的Path。 57 58 ```js 59 const canvas = context.canvas 60 let height_ = 1200 61 let width_ = 600 62 let len = height_ / 4 63 let aX = width_ / 2 64 let aY = height_ / 4 65 let dX = aX - len * Math.sin(18.0) 66 let dY = aY + len * Math.cos(18.0) 67 let cX = aX + len * Math.sin(18.0) 68 let cY = dY 69 let bX = aX + (len / 2.0) 70 let bY = aY + Math.sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0)) 71 let eX = aX - (len / 2.0) 72 let eY = bY; 73 74 // 创建一个path对象,然后使用接口连接成一个五角星形状 75 let path = new drawing.Path() 76 77 // 指定path的起始位置 78 path.moveTo(aX, aY) 79 80 // 用直线连接到目标点 81 path.lineTo(bX, bY) 82 path.lineTo(cX, cY) 83 path.lineTo(dX, dY) 84 path.lineTo(eX, eY) 85 86 // 闭合形状,path绘制完毕 87 path.close() 88 ``` 89 903. **设置画笔和画刷样式**。使用`Pen`接口创建一个画笔实例pen,并设置抗锯齿、颜色、线宽等属性,画笔用于形状边框线的绘制。使用`Brush`接口创建一个画刷实例brush,并设置填充颜色,画刷用于形状内部的填充。使用canvas中的`attachPen`和`attachBrush`接口将画笔画刷的实例设置到画布实例中。 91 92 ```js 93 // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制 94 let pen = new drawing.Pen() 95 pen.setAntiAlias(true) 96 let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 } 97 pen.setColor(pen_color) 98 pen.setStrokeWidth(10.0) 99 100 // 将Pen画笔设置到canvas中 101 canvas.attachPen(pen) 102 103 // 创建一个画刷Brush对象,Brush对象用于形状的填充 104 let brush = new drawing.Brush() 105 let brush_color : common2D.Color = { alpha: 0xFF, red: 0x00, green: 0xFF, blue: 0x00 } 106 brush.setColor(brush_color) 107 108 // 将Brush画刷设置到canvas中 109 canvas.attachBrush(brush) 110 ``` 111 1124. **绘制Path形状**。使用canvas中的`drawPath`接口将五角星绘制到画布上。 113 114 ```js 115 // 绘制path 116 canvas.drawPath(path) 117 ``` 118 1195. **创建MyRenderNode对象**。以上1到4步构建出了MyRenderNode类并在其中定义了绘图的主要函数,接下来创建一个MyRenderNode对象,并设置它的像素格式。 120 121 ```js 122 // 创建一个MyRenderNode对象 123 const newNode = new MyRenderNode() 124 // 定义newNode的像素格式 125 newNode.frame = { x: 100, y: 100, width: 200, height: 800 } 126 newNode.pivot = { x: 0.2, y: 0.8 } 127 newNode.scale = { x: 1, y: 1 } 128 ``` 129 1306. **绘制矩形**。使用canvas中的`drawRect`接口绘制矩形。 131 132 ```js 133 class RectRenderNode extends RenderNode { 134 async draw(context: DrawContext) { 135 const canvas = context.canvas 136 const pen = new drawing.Pen() 137 pen.setStrokeWidth(5) 138 pen.setColor({alpha: 255, red: 255, green: 0, blue: 0}) 139 canvas.attachPen(pen) 140 canvas.drawRect({ left : 200, right : 500, top : 300, bottom : 900}) 141 } 142 } 143 // 创建一个RectRenderNode对象 144 const rectNode = new RectRenderNode() 145 // 定义rectNode的像素格式 146 rectNode.frame = { x: 90, y: 100, width: 200, height: 800 } 147 rectNode.pivot = { x: 0.2, y: 0.8 } 148 rectNode.scale = { x: 1, y: 1 } 149 ``` 150 1517. **绘制文字**。使用canvas中的`drawTextBlob`接口绘制文字。 152 153 ```js 154 class TextRenderNode extends RenderNode { 155 async draw(context: DrawContext) { 156 const canvas = context.canvas 157 const brush = new drawing.Brush() 158 brush.setColor({alpha: 255, red: 255, green: 0, blue: 0}) 159 const font = new drawing.Font() 160 font.setSize(100) 161 const textBlob = drawing.TextBlob.makeFromString("Hello World", font, drawing.TextEncoding.TEXT_ENCODING_UTF8) 162 canvas.attachBrush(brush) 163 canvas.drawTextBlob(textBlob, 90, 500) 164 } 165 } 166 // 创建一个TextRenderNode对象 167 const textNode = new TextRenderNode() 168 // 定义textNode的像素格式 169 textNode.frame = { x: 90, y: 100, width: 200, height: 800 } 170 textNode.pivot = { x: 0.2, y: 0.8 } 171 textNode.scale = { x: 1, y: 1 } 172 ``` 173 1748. **创建NodeController子类**。创建`NodeController`的子类`MyNodeController`,并在其中定义创建`FrameNode`的函数。`NodeController`定义了节点容器的控制器,控制着容器里在生命周期中的节点。`FrameNode`定义了节点的基本类型,并包含一个`RenderNode`。 175 176 ```js 177 class MyNodeController extends NodeController { 178 private rootNode: FrameNode | null = null; 179 180 makeNode(uiContext: UIContext): FrameNode { 181 this.rootNode = new FrameNode(uiContext) 182 if (this.rootNode == null) { 183 return this.rootNode 184 } 185 const renderNode = this.rootNode.getRenderNode() 186 if (renderNode != null) { 187 renderNode.frame = { x: 0, y: 0, width: 10, height: 500 } 188 renderNode.pivot = { x: 50, y: 50 } 189 } 190 return this.rootNode 191 } 192 } 193 ``` 194 1959. **创建添加节点的接口**。在第8步中创建的`MyNodeController`类中创建添加`RenderNode`的接口。 196 197 ```js 198 addNode(node: RenderNode): void { 199 if (this.rootNode == null) { 200 return 201 } 202 const renderNode = this.rootNode.getRenderNode() 203 if (renderNode != null) { 204 renderNode.appendChild(node) 205 } 206 } 207 ``` 208 20910. **创建删除节点的接口**。在第8步中创建的`MyNodeController`类中创建删除`RenderNode`的接口。 210 211 ```js 212 clearNodes(): void { 213 if (this.rootNode == null) { 214 return 215 } 216 const renderNode = this.rootNode.getRenderNode() 217 if (renderNode != null) { 218 renderNode.clearChildren() 219 } 220 } 221 ``` 222 22311. **绘制图形和文字**。创建`MyNodeController`实例并将其存入`NodeContainer`,添加button控件供用户点击,并调用已定义的接口。 224 225 ```js 226 @Entry 227 @Component 228 struct RenderTest { 229 private myNodeController: MyNodeController = new MyNodeController() 230 build() { 231 Column() { 232 Row() { 233 NodeContainer(this.myNodeController) 234 .height('100%') 235 Button("Draw Path") 236 .margin({ bottom: 200, right: 12 }) 237 .onClick(() => { 238 this.myNodeController.clearNodes() 239 this.myNodeController.addNode(newNode) 240 }) 241 Button("Draw Rect") 242 .margin({ bottom: 200, right: 12 }) 243 .onClick(() => { 244 this.myNodeController.clearNodes() 245 this.myNodeController.addNode(rectNode) 246 }) 247 Button("Draw Text") 248 .margin({ bottom: 200, right: 12 }) 249 .onClick(() => { 250 this.myNodeController.clearNodes() 251 this.myNodeController.addNode(textNode) 252 }) 253 } 254 .width('100%') 255 .justifyContent(FlexAlign.Center) 256 .shadow(ShadowStyle.OUTER_DEFAULT_SM) 257 .alignItems(VerticalAlign.Bottom) 258 .layoutWeight(1) 259 } 260 } 261 } 262 ``` 263 26412. 绘制与显示的效果图如下: 265 266 | 主页 | 绘制五角星 | 绘制矩形 | 绘制文字 | 267 | ------------------------------------ | ----------------------------------------------- | ------------------------------------ | ------------------------------------ | 268 |  |  |  |  | 269 270## 相关实例 271 272针对Drawing图形绘制和显示的更多开发,可参考以下相关示例: 273 274- [字体文本展开(ArkTS)(API12)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-5.0.2-Release/code/BasicFeature/Graphics/Graphics2d/ExpandText) 275 276- [字体绘制(ArkTS)(API12)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-5.0.2-Release/code/BasicFeature/Graphics/Graphics2d/PaintVerbatim) 277 278<!--RP1--><!--RP1End--> 279