1# 复杂文本绘制与显示(ArkTS) 2<!--Kit: ArkGraphics 2D--> 3<!--Subsystem: Graphics--> 4<!--Owner: @oh_wangxk; @gmiao522; @Lem0nC--> 5<!--Designer: @liumingxiang--> 6<!--Tester: @yhl0101--> 7<!--Adviser: @ge-yafang--> 8在进行文本绘制时,可以通过选择合适的字体、大小和颜色完成简单文本的绘制与显示;此外,还支持通过设置其他丰富的样式、语言、段落等进行复杂文本的绘制。 9 10复杂文本绘制主要包含以下几个场景: 11 12- 多语言文本绘制与显示 13 14- 多行文本绘制与显示 15 16- 多样式文本绘制与显示 17 18 19## 多语言文本绘制与显示 20 21多语言支持是全球化应用的基础。多语言文本绘制需要支持不同语言的字符集及其独特的显示需求,例如右到左语言(如阿拉伯语)或竖排文本(如中文)。开发者需要理解不同语言的渲染特性,确保文本的正确显示。 22 23 24在多语言文本使用的场景下,主要通过指定[TextStyle](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#textstyle)文本样式中的**locale**字段来实现,可直接通过locale字段的值优先匹配对应字体,跳过遍历列表匹配字体的过程,从而降低匹配时间和内存使用。 25 26 27### 开发步骤 28 291. 通过context获取到Canvas画布对象。 30 31 ```ts 32 let canvas = context.canvas; 33 ``` 34 352. 初始化文本样式。 36 37 ```ts 38 let myTextStyle: text.TextStyle = { 39 color: { 40 alpha: 255, 41 red: 255, 42 green: 0, 43 blue: 0 44 }, 45 fontSize: 50, 46 // 设置语言偏好为简体中文 47 locale: "zh-Hans" 48 }; 49 ``` 50 513. 初始化段落样式。 52 53 ```ts 54 let myParagraphStyle: text.ParagraphStyle = { 55 textStyle: myTextStyle, 56 }; 57 ``` 58 594. 初始化段落对象,并添加文本。 60 61 ```ts 62 let fontCollection = text.FontCollection.getGlobalInstance(); 63 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 64 // 更新文本样式 65 paragraphBuilder.pushStyle(myTextStyle); 66 // 添加文本 67 paragraphBuilder.addText("你好,世界"); 68 ``` 69 705. 排版段落并进行文本绘制。 71 72 ```ts 73 // 生成段落 74 let paragraph = paragraphBuilder.build(); 75 // 布局 76 paragraph.layoutSync(1250); 77 // 绘制文本 78 paragraph.paint(canvas, 10, 0); 79 ``` 80 81 82### 完整示例 83 84此示例中,要绘制的文本为简体中文,将语言偏好设置为简体中文,在匹配文字字体时,会优先匹配简体,从而提高绘制的效率。 85 86```ts 87import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' 88import { UIContext } from '@kit.ArkUI' 89import { drawing } from '@kit.ArkGraphics2D' 90import { text } from '@kit.ArkGraphics2D' 91import { image } from '@kit.ImageKit' 92import { common2D } from '@kit.ArkGraphics2D' 93 94// 创建一个MyRenderNode类,并绘制文本。 95class MyRenderNode extends RenderNode { 96 async draw(context: DrawContext) { 97 // 绘制代码逻辑写在这里 98 let canvas = context.canvas; 99 100 let myTextStyle: text.TextStyle = { 101 color: { 102 alpha: 255, 103 red: 255, 104 green: 0, 105 blue: 0 106 }, 107 fontSize: 50, 108 // 设置语言偏好为简体中文 109 locale: "zh-Hans" 110 }; 111 112 let myParagraphStyle: text.ParagraphStyle = { 113 textStyle: myTextStyle, 114 }; 115 let fontCollection = text.FontCollection.getGlobalInstance(); 116 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 117 // 更新文本样式 118 paragraphBuilder.pushStyle(myTextStyle); 119 // 添加文本 120 paragraphBuilder.addText("你好,世界"); 121 // 生成段落 122 let paragraph = paragraphBuilder.build(); 123 // 布局 124 paragraph.layoutSync(1250); 125 // 绘制文本 126 paragraph.paint(canvas, 10, 0); 127 } 128} 129 130// 创建一个MyRenderNode对象 131const textNode = new MyRenderNode() 132// 定义newNode的像素格式 133textNode.frame = { 134 x: 0, 135 y: 0, 136 width: 400, 137 height: 600 138} 139textNode.pivot = { x: 0.2, y: 0.8 } 140textNode.scale = { x: 1, y: 1 } 141 142class MyNodeController extends NodeController { 143 private rootNode: FrameNode | null = null; 144 145 makeNode(uiContext: UIContext): FrameNode { 146 this.rootNode = new FrameNode(uiContext) 147 if (this.rootNode == null) { 148 return this.rootNode 149 } 150 const renderNode = this.rootNode.getRenderNode() 151 if (renderNode != null) { 152 renderNode.frame = { 153 x: 0, 154 y: 0, 155 width: 10, 156 height: 500 157 } 158 } 159 return this.rootNode 160 } 161 162 addNode(node: RenderNode): void { 163 if (this.rootNode == null) { 164 return 165 } 166 const renderNode = this.rootNode.getRenderNode() 167 if (renderNode != null) { 168 renderNode.appendChild(node) 169 } 170 } 171 172 clearNodes(): void { 173 if (this.rootNode == null) { 174 return 175 } 176 const renderNode = this.rootNode.getRenderNode() 177 if (renderNode != null) { 178 renderNode.clearChildren() 179 } 180 } 181} 182 183let myNodeController: MyNodeController = new MyNodeController() 184 185async function performTask() { 186 myNodeController.clearNodes() 187 myNodeController.addNode(textNode) 188} 189 190@Entry 191@Component 192struct Font08 { 193 @State src: Resource = $r('app.media.startIcon') 194 build() { 195 Column() { 196 Row() { 197 NodeContainer(myNodeController) 198 .height('100%') 199 .width('100%') 200 Image(this.src) 201 .width('0%').height('0%') 202 .onComplete( 203 () => { 204 performTask(); 205 }) 206 } 207 .width('100%') 208 } 209 } 210} 211``` 212 213 214### 效果展示 215 216 217 218 219## 多行文本绘制与显示 220 221多行文本相对于单行文本比较复杂,一般针对多行文本,需要进行文本排版、断词策略设置、文本对齐方式、最大行数限制等,主要通过设置段落样式实现。 222 223 224### 实现说明 225 226**段落样式**([ParagraphStyle](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#paragraphstyle))是对多行文本中每段内容的样式设置,包括断词策略、文本对齐方式、最大行数限制等。开发者可以通过对不同段落进行样式化,以提高文本的可读性和美观性。 227 228 229### 开发步骤 230 2311. 通过context获取到Canvas画布对象。 232 233 ```ts 234 // 绘制代码逻辑写在这里 235 let canvas = context.canvas; 236 ``` 237 2382. 初始化文本样式。 239 240 ```ts 241 let myTextStyle: text.TextStyle = { 242 color: { 243 alpha: 255, 244 red: 255, 245 green: 0, 246 blue: 0 247 }, 248 fontSize: 50, 249 // 当wordBreak为text.WordBreak.BREAK_HYPHEN时,需要设置语言偏好,段落会在不同语言偏好下呈现不同的文本断词效果 250 locale: "en-gb" 251 }; 252 ``` 253 2543. 初始化段落样式。 255 256 ```ts 257 let myParagraphStyle: text.ParagraphStyle = { 258 textStyle: myTextStyle, 259 // 文本对齐方式 260 align: text.TextAlign.LEFT, 261 // 最大行数 262 maxLines: 3, 263 // 断词策略 264 wordBreak: text.WordBreak.BREAK_WORD 265 }; 266 ``` 267 2684. 初始化段落对象,并添加占位符和文本。 269 270 ```ts 271 let fontCollection = text.FontCollection.getGlobalInstance(); 272 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 273 // 更新文本样式 274 paragraphBuilder.pushStyle(myTextStyle); 275 // 添加文本 276 paragraphBuilder.addText("Hello World Hello World Hello World Hello World Hello World Hello World " + 277 "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World " + 278 "Hello World Hello World Hello World Hello World Hello World "); 279 ``` 280 2815. 排版段落并进行文本绘制。 282 283 ```ts 284 // 生成段落 285 let paragraph = paragraphBuilder.build(); 286 // 布局 287 paragraph.layoutSync(1250); 288 // 绘制文本 289 paragraph.paint(canvas, 10, 0); 290 ``` 291 292 293### 完整示例 294 295```ts 296import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' 297import { UIContext } from '@kit.ArkUI' 298import { drawing } from '@kit.ArkGraphics2D' 299import { text } from '@kit.ArkGraphics2D' 300import { image } from '@kit.ImageKit' 301import { common2D } from '@kit.ArkGraphics2D' 302 303// 创建一个MyRenderNode类,并绘制文本。 304class MyRenderNode extends RenderNode { 305 async draw(context: DrawContext) { 306 // 绘制代码逻辑写在这里 307 let canvas = context.canvas; 308 309 let myTextStyle: text.TextStyle = { 310 color: { 311 alpha: 255, 312 red: 255, 313 green: 0, 314 blue: 0 315 }, 316 fontSize: 50, 317 // 当wordBreak为text.WordBreak.BREAK_HYPHEN时,需要为段落设置语言偏好,段落会在不同语言偏好下呈现不同的文本断词效果 318 locale: "en-gb" 319 }; 320 321 let myParagraphStyle: text.ParagraphStyle = { 322 textStyle: myTextStyle, 323 // 文本对齐方式 324 align: text.TextAlign.LEFT, 325 // 最大行数 326 maxLines: 3, 327 // 断词策略 328 wordBreak: text.WordBreak.BREAK_WORD 329 }; 330 let fontCollection = text.FontCollection.getGlobalInstance(); 331 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 332 // 更新文本样式 333 paragraphBuilder.pushStyle(myTextStyle); 334 // 添加文本 335 paragraphBuilder.addText("Hello World Hello World Hello World Hello World Hello World Hello World " + 336 "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World " + 337 "Hello World Hello World Hello World Hello World Hello World "); 338 // 当wordBreak为text.WordBreak.BREAK_HYPHEN时,替换文本内容为: 339 // paragraphBuilder.addText("Modern embedded systems require robust communication protocols and efficient memory " + 340 // "management strategies. Developers often face challenges in optimizing performance while maintaining " + 341 // "modularity and portability. By leveraging a layered architecture and structured logging, applications can " + 342 // "detect anomalies and respond quickly to faults. This approach enhances reliability, especially in " + 343 // "time-critical environments such as IoT devices and real-time operating systems."); 344 345 // 生成段落 346 let paragraph = paragraphBuilder.build(); 347 // 布局 348 paragraph.layoutSync(1250); 349 // 绘制文本 350 paragraph.paint(canvas, 10, 0); 351 } 352} 353 354// 创建一个MyRenderNode对象 355const textNode = new MyRenderNode() 356// 定义newNode的像素格式 357textNode.frame = { 358 x: 0, 359 y: 0, 360 width: 400, 361 height: 600 362} 363textNode.pivot = { x: 0.2, y: 0.8 } 364textNode.scale = { x: 1, y: 1 } 365 366class MyNodeController extends NodeController { 367 private rootNode: FrameNode | null = null; 368 369 makeNode(uiContext: UIContext): FrameNode { 370 this.rootNode = new FrameNode(uiContext) 371 if (this.rootNode == null) { 372 return this.rootNode 373 } 374 const renderNode = this.rootNode.getRenderNode() 375 if (renderNode != null) { 376 renderNode.frame = { 377 x: 0, 378 y: 0, 379 width: 10, 380 height: 500 381 } 382 } 383 return this.rootNode 384 } 385 386 addNode(node: RenderNode): void { 387 if (this.rootNode == null) { 388 return 389 } 390 const renderNode = this.rootNode.getRenderNode() 391 if (renderNode != null) { 392 renderNode.appendChild(node) 393 } 394 } 395 396 clearNodes(): void { 397 if (this.rootNode == null) { 398 return 399 } 400 const renderNode = this.rootNode.getRenderNode() 401 if (renderNode != null) { 402 renderNode.clearChildren() 403 } 404 } 405} 406 407let myNodeController: MyNodeController = new MyNodeController() 408 409async function performTask() { 410 myNodeController.clearNodes() 411 myNodeController.addNode(textNode) 412} 413 414@Entry 415@Component 416struct Font08 { 417 @State src: Resource = $r('app.media.startIcon') 418 build() { 419 Column() { 420 Row() { 421 NodeContainer(myNodeController) 422 .height('100%') 423 .width('100%') 424 Image(this.src) 425 .width('0%').height('0%') 426 .onComplete( 427 () => { 428 performTask(); 429 }) 430 } 431 .width('100%') 432 } 433 } 434} 435``` 436 437 438### 效果展示 439 440| 段落样式设置(断词策略、文本对齐方式、最大行数限制) | 效果示意 | 441| -------- | -------- | 442| 文本对齐方式为text.TextAlign.LEFT,最大行数为3,断词策略为text.WordBreak.BREAK_WORD。 |  | 443| 文本对齐方式为text.TextAlign.RIGHT,最大行数为3,断词策略为text.WordBreak.BREAK_WORD。 |  | 444| 文本对齐方式为text.TextAlign.JUSTIFY,最大行数为10,断词策略为text.WordBreak.BREAK_WORD。 |  | 445| 文本对齐方式为text.TextAlign.LEFT,最大行数为3,断词策略为text.WordBreak.BREAK_ALL。 |  | 446| 文本对齐方式为text.TextAlign.LEFT,最大行数为10,断词策略为text.WordBreak.BREAK_ALL。 |  | 447| 文本对齐方式为text.TextAlign.LEFT,最大行数为10,断词策略为text.WordBreak.BREAK_HYPHEN,<br/>不设置语言偏好。段落无连字符“-”断词效果。 |  | 448| 文本对齐方式为text.TextAlign.LEFT,最大行数为10,断词策略为text.WordBreak.BREAK_HYPHEN,<br/>语言偏好为en-gb(英式英语)。段落产生连字符“-”断词效果,并根据语言偏好呈现英式语言环境断词效果。 |  | 449| 文本对齐方式为text.TextAlign.LEFT,最大行数为10,断词策略为text.WordBreak.BREAK_HYPHEN,<br/>语言偏好为en-us(美式英语)。段落产生连字符“-”断词效果,并根据语言偏好呈现美式语言环境断词效果。 |  | 450 451 452## 多样式文本绘制与显示 453 454除基本文字、排版属性之外,针对应用中不同文本的设计,开发者可能需要设置使用不同的绘制样式或能力,以凸显对应文本的独特表现或风格,此时可以结合使用多种绘制样式进行文本的渲染。 455 456当前支持的多样式绘制及各绘制样式侧重效果如下: 457 458- **装饰线样式绘制:** 主要通过不同的线条样式对文本进行装饰,可以使文本更加突出,富有表现力。 459 460- **字体特性绘制:** 主要通过字体的变化,包括粗细、斜体等特性来改变文本的外观,增强文本的可读性和美观性。 461 462- **可变字体绘制:** 对应提供文本在不同的显示环境和设备上灵活调整的能力,可满足更为精细的视觉效果。 463 464- **文本阴影绘制:** 主要通过在文本周围添加阴影效果,以提升文本的层次感和立体感,从而使文本更具吸引力。 465 466- **占位符绘制:** 可以在不确定文本内容时保持文本布局的稳定性,使得文本显示更为流畅和自然。 467 468- **自动间距绘制:** 可以在一些字符混排切换的地方自动添加额外间距,提升阅读体验。 469 470- **垂直对齐:** 调整文本在垂直方向排版位置,提升排版质量。 471 472- **上下标:** 可以将任意字符处理成上标或下标,更精准表达文本含义。 473 474- **高对比度文字绘制:** 主要通过将深色文字变黑、浅色文字变白,增强文本的对比效果。 475 476### 装饰线 477 478装饰线([Decoration](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#decoration))是指在文本上方、下方或中间添加的装饰性线条,当前支持上划线、下划线、删除线。 479 480可以通过添加文本装饰线,提升文本的视觉效果和可读性。 481 482使用装饰线需要初始化装饰线样式对象,并添加到文本样式中,从而在文本绘制时生效。 483 484具体使用效果可参见下文[示例一](#示例一装饰线字体特征)。 485 486### 字体特征 487 488**字体特征**([FontFeature](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#fontfeature))绘制专注于在文本渲染过程中对字体特性(如粗体、斜体、字体变种等)的处理,允许字体在不同的排版场景下表现出不同的效果,可用于增强文本的表现力,使其更符合设计和阅读需求。 489 490常见的**FontFeature**包含有liga、frac、case等,需要对应的ttf文件支持才能正常使能。 491 492具体使用效果可参见下文[示例一](#示例一装饰线字体特征)。 493 494### 可变字体 495 496**可变字体**([FontVariation](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#fontvariation))是一种在一个字体文件中包含多个字形变体的字体格式,允许在一个字体文件内灵活地调整字体的各种属性(如字重、字宽、斜体等)。 497 498与传统字体文件(每种变体需要一个独立的文件)不同,可变字体在一个字体文件中包含多个变体轴,可通过使用可变字体实现文本渲染绘制时的平滑过渡。 499 500具体使用效果可参见下文[示例二](#示例二可变字体文本阴影占位符)。 501 502### 文本阴影 503 504**文本阴影**([TextShadow](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#textshadow))为文本提供了深度感,使得文本在背景上更具立体感。通常用于提升文本的视觉吸引力或增强可读性,尤其是在色彩对比度较低的场景下。 505 506其中,TextShadow有三个属性,分别为阴影颜色color、阴影基于当前文本的偏移位置point、阴影半径blurRadius。 507 508使用阴影效果需要在文本样式中设置对应的阴影效果数组,从而在文本绘制时生效。 509 510具体使用效果可参见下文[示例二](#示例二可变字体文本阴影占位符)。 511 512### 占位符 513 514占位符绘制用于处理文本中占位符符号的渲染。 515 516占位符也是用来实现图文混排的关键,是指在实际图像或内容注册之前,用来预先提供或替代某个位置的视觉元素。 517 518具体使用效果可参见下文[示例二](#示例二可变字体文本阴影占位符)。 519 520### 自动间距 521 522使能自动间距,则会在文本排版时自动调整CJK(中文字符、日文字符、韩文字符)与西文(拉丁字母、西里尔字母、希腊字母)、CJK与数字、CJK与版权符号、版权符号与数字、版权符号与西文之间的间距。例如,在中英文混排场景中,使能自动间距即可在中英文切换的地方自动添加额外间距,提升阅读体验。 523关键示例如下: 524```ts 525let myParagraphStyle: text.ParagraphStyle = { 526 autoSpace: true 527}; 528``` 529 530### 垂直对齐 531 532垂直对齐用于调整文本在一行中垂直方向的排版位置。开启行高缩放或行内存在不同字号文本混排时使能垂直对齐,可以让文本实现顶部对齐、居中对齐、底部对齐或基线对齐(默认)。关键代码如下: 533 534```ts 535let myParagraphStyle: text.ParagraphStyle = { 536 verticalAlign: text.TextVerticalAlign.CENTER 537}; 538``` 539 540具体使用效果可参见下文[示例三](#示例三垂直对齐)。 541 542### 上下标 543 544使能上下标,能将文本作为上标或下标参与排版。一般用于数学公式、化学式等场景。关键代码如下: 545 546```ts 547let superScriptStyle: text.TextStyle = { 548 badgeType: text.TextBadgeType.TEXT_SUPERSCRIPT 549}; 550``` 551 552具体使用效果可参见下文[示例四](#示例四上下标文本)。 553 554### 高对比度 555 556高对比度可将深色文字变黑、浅色文字变白。开发者可选择开启或关闭应用的高对比度文字渲染,或遵循系统设置中的高对比度文字配置。 557 558高对比度模式有3种,具体参考[TextHighContrast](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#texthighcontrast20)。 559 560具体使用效果可参见下文[示例五](#示例五高对比度)。 561 562### 示例一(装饰线、字体特征) 563这里以文本样式中的装饰线和字体特征为例,呈现多样式文本的绘制与显示。 564 565```ts 566import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' 567import { UIContext } from '@kit.ArkUI' 568import { drawing } from '@kit.ArkGraphics2D' 569import { text } from '@kit.ArkGraphics2D' 570import { image } from '@kit.ImageKit' 571import { common2D } from '@kit.ArkGraphics2D' 572 573// 创建一个MyRenderNode类,并绘制文本。 574class MyRenderNode extends RenderNode { 575 async draw(context: DrawContext) { 576 let canvas = context.canvas; 577 578 // 初始化装饰线对象 579 let decorations: text.Decoration = 580 { 581 // 装饰线类型,支持上划线、下划线、删除线 582 textDecoration: text.TextDecorationType.UNDERLINE, 583 // 装饰线颜色 584 color: { 585 alpha: 255, 586 red: 255, 587 green: 0, 588 blue: 0 589 }, 590 // 装饰线样式,支持波浪,虚线,直线等 591 decorationStyle:text.TextDecorationStyle.SOLID, 592 // 装饰线的高度 593 decorationThicknessScale: 1 594 }; 595 596 let myTextStyle: text.TextStyle = { 597 color: { 598 alpha: 255, 599 red: 255, 600 green: 0, 601 blue: 0 602 }, 603 fontSize: 300, 604 // 设置装饰线 605 decoration: decorations, 606 // 开启字体特征 607 fontFeatures: [{name: 'frac', value: 1}] 608 }; 609 610 let myParagraphStyle: text.ParagraphStyle = { 611 textStyle: myTextStyle, 612 }; 613 614 let fontCollection = text.FontCollection.getGlobalInstance(); 615 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 616 617 // 更新文本样式 618 paragraphBuilder.pushStyle(myTextStyle); 619 // 添加文本 620 paragraphBuilder.addText("1/2 1/3 1/4 "); 621 622 // 生成段落 623 let paragraph = paragraphBuilder.build(); 624 // 布局 625 paragraph.layoutSync(1250); 626 // 绘制文本 627 paragraph.paint(canvas, 0, 0); 628 } 629} 630 631// 创建一个MyRenderNode对象 632const textNode = new MyRenderNode() 633// 定义newNode的像素格式 634textNode.frame = { 635 x: 0, 636 y: 0, 637 width: 400, 638 height: 600 639} 640textNode.pivot = { x: 0.2, y: 0.8 } 641textNode.scale = { x: 1, y: 1 } 642 643class MyNodeController extends NodeController { 644 private rootNode: FrameNode | null = null; 645 646 makeNode(uiContext: UIContext): FrameNode { 647 this.rootNode = new FrameNode(uiContext) 648 if (this.rootNode == null) { 649 return this.rootNode 650 } 651 const renderNode = this.rootNode.getRenderNode() 652 if (renderNode != null) { 653 renderNode.frame = { 654 x: 0, 655 y: 0, 656 width: 10, 657 height: 500 658 } 659 } 660 return this.rootNode 661 } 662 663 addNode(node: RenderNode): void { 664 if (this.rootNode == null) { 665 return 666 } 667 const renderNode = this.rootNode.getRenderNode() 668 if (renderNode != null) { 669 renderNode.appendChild(node) 670 } 671 } 672 673 clearNodes(): void { 674 if (this.rootNode == null) { 675 return 676 } 677 const renderNode = this.rootNode.getRenderNode() 678 if (renderNode != null) { 679 renderNode.clearChildren() 680 } 681 } 682} 683 684let myNodeController: MyNodeController = new MyNodeController() 685 686async function performTask() { 687 myNodeController.clearNodes() 688 myNodeController.addNode(textNode) 689} 690 691@Entry 692@Component 693struct Font08 { 694 @State src: Resource = $r('app.media.startIcon') 695 build() { 696 Column() { 697 Row() { 698 NodeContainer(myNodeController) 699 .height('100%') 700 .width('100%') 701 Image(this.src) 702 .width('0%').height('0%') 703 .onComplete( 704 () => { 705 performTask(); 706 }) 707 } 708 .width('100%') 709 } 710 } 711} 712``` 713 714 715具体示意效果如下所示: 716 717| 样式设置(装饰线样式、字体特征) | 示意效果 | 718| -------- | -------- | 719| 不开启装饰线和字体特征 |  | 720| 开启装饰线和字体特征 |  | 721 722### 示例二(可变字体、文本阴影、占位符) 723这里以可变字体、文本阴影、占位符三个特性为例,呈现多样式文本的绘制与显示。 724```ts 725import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI' 726import { UIContext } from '@kit.ArkUI' 727import { drawing } from '@kit.ArkGraphics2D' 728import { text } from '@kit.ArkGraphics2D' 729import { image } from '@kit.ImageKit' 730import { common2D } from '@kit.ArkGraphics2D' 731 732// 创建一个MyRenderNode类,并绘制文本。 733class MyRenderNode extends RenderNode { 734 async draw(context: DrawContext) { 735 let canvas = context.canvas; 736 737 let myTextStyle: text.TextStyle = { 738 color: { 739 alpha: 255, 740 red: 255, 741 green: 0, 742 blue: 0 743 }, 744 fontSize: 150, 745 // 可变字体 746 fontVariations: [{axis: 'wght', value: 555}], 747 // 文本阴影 748 textShadows: [{color: { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }, point: {x:10,y:10}, blurRadius: 10}], 749 }; 750 751 let myParagraphStyle: text.ParagraphStyle = { 752 textStyle: myTextStyle, 753 }; 754 755 let fontCollection = text.FontCollection.getGlobalInstance(); 756 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 757 758 // 初始化占位符对象 759 let myPlaceholderSpan: text.PlaceholderSpan = { 760 // 宽度 761 width: 300, 762 // 高度 763 height: 300, 764 // 基线对齐策略 765 align: text.PlaceholderAlignment.BOTTOM_OF_ROW_BOX, 766 // 使用的文本基线类型 767 baseline: text.TextBaseline.ALPHABETIC, 768 // 相比基线的偏移量。只有对齐策略是OFFSET_AT_BASELINE时生效 769 baselineOffset: 100 770 }; 771 // 添加占位符 772 paragraphBuilder.addPlaceholder(myPlaceholderSpan) 773 774 // 更新文本样式 775 paragraphBuilder.pushStyle(myTextStyle); 776 // 添加文本 777 paragraphBuilder.addText("Hello Test"); 778 779 // 生成段落 780 let paragraph = paragraphBuilder.build(); 781 // 布局 782 paragraph.layoutSync(1250); 783 // 绘制文本 784 paragraph.paint(canvas, 0, 0); 785 786 //获取全部占位符的数组 787 let placeholderRects = paragraph.getRectsForPlaceholders(); 788 // 获取第一个占位符的左边界 789 let left = placeholderRects[0].rect.left 790 // 获取第一个占位符的上边界 791 let top = placeholderRects[0].rect.top 792 // 获取第一个占位符的右边界 793 let right = placeholderRects[0].rect.right 794 // 获取第一个占位符的下边界 795 let bottom = placeholderRects[0].rect.bottom 796 let pen: drawing.Pen = new drawing.Pen() 797 let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 } 798 pen.setColor(pen_color) 799 canvas.attachPen(pen) 800 // 使用draw方法绘制占位符矩形框 801 canvas.drawRect(left,top,right,bottom) 802 } 803} 804 805// 创建一个MyRenderNode对象 806const textNode = new MyRenderNode() 807// 定义newNode的像素格式 808textNode.frame = { 809 x: 0, 810 y: 0, 811 width: 400, 812 height: 600 813} 814textNode.pivot = { x: 0.2, y: 0.8 } 815textNode.scale = { x: 1, y: 1 } 816 817class MyNodeController extends NodeController { 818 private rootNode: FrameNode | null = null; 819 820 makeNode(uiContext: UIContext): FrameNode { 821 this.rootNode = new FrameNode(uiContext) 822 if (this.rootNode == null) { 823 return this.rootNode 824 } 825 const renderNode = this.rootNode.getRenderNode() 826 if (renderNode != null) { 827 renderNode.frame = { 828 x: 0, 829 y: 0, 830 width: 10, 831 height: 500 832 } 833 } 834 return this.rootNode 835 } 836 837 addNode(node: RenderNode): void { 838 if (this.rootNode == null) { 839 return 840 } 841 const renderNode = this.rootNode.getRenderNode() 842 if (renderNode != null) { 843 renderNode.appendChild(node) 844 } 845 } 846 847 clearNodes(): void { 848 if (this.rootNode == null) { 849 return 850 } 851 const renderNode = this.rootNode.getRenderNode() 852 if (renderNode != null) { 853 renderNode.clearChildren() 854 } 855 } 856} 857 858let myNodeController: MyNodeController = new MyNodeController() 859 860async function performTask() { 861 myNodeController.clearNodes() 862 myNodeController.addNode(textNode) 863} 864 865@Entry 866@Component 867struct Font08 { 868 @State src: Resource = $r('app.media.startIcon') 869 build() { 870 Column() { 871 Row() { 872 NodeContainer(myNodeController) 873 .height('100%') 874 .width('100%') 875 Image(this.src) 876 .width('0%').height('0%') 877 .onComplete( 878 () => { 879 performTask(); 880 }) 881 } 882 .width('100%') 883 } 884 } 885} 886``` 887 888具体示意效果如下所示: 889 890| 样式设置(可变字体、文本阴影、占位符) | 示意效果 | 891| -------- | -------- | 892| 不开启可变字体和文本阴影,不使用占位符 |  | 893| 开启可变字体和文本阴影,使用占位符 |  | 894 895### 示例三(垂直对齐) 896这里以垂直对齐-居中对齐特性为例,呈现文本垂直方向排版的特性。 897 898```ts 899import { NodeController, FrameNode, RenderNode, DrawContext, UIContext } from '@kit.ArkUI' 900import { drawing, text, common2D } from '@kit.ArkGraphics2D' 901import { image } from '@kit.ImageKit' 902 903// 创建一个MyRenderNode类,并绘制文本。 904class MyRenderNode extends RenderNode { 905 async draw(context: DrawContext) { 906 let canvas = context.canvas; 907 908 let myTextStyle: text.TextStyle = { 909 color: { 910 alpha: 255, 911 red: 255, 912 green: 0, 913 blue: 0 914 }, 915 fontSize: 30, 916 // 开启行高缩放 917 heightOnly: true, 918 // 行高缩放系数为字号的2倍 919 heightScale: 2 920 }; 921 922 let myParagraphStyle: text.ParagraphStyle = { 923 textStyle: myTextStyle, 924 // 设置垂直对齐-居中对齐模式 925 verticalAlign: text.TextVerticalAlign.CENTER, 926 }; 927 928 let fontCollection = text.FontCollection.getGlobalInstance(); 929 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 930 931 // 设置待排版文本要应用的样式 932 paragraphBuilder.pushStyle(myTextStyle); 933 // 添加文本 934 paragraphBuilder.addText("VerticalAlignment-center"); 935 936 // 生成段落 937 let paragraph = paragraphBuilder.build(); 938 // 布局 939 paragraph.layoutSync(1000); 940 // 绘制文本 941 paragraph.paint(canvas, 0, 0); 942 } 943} 944 945// 创建一个MyRenderNode对象 946const textNode = new MyRenderNode() 947// 定义newNode的像素格式 948textNode.frame = { 949 x: 0, 950 y: 0, 951 width: 400, 952 height: 600 953} 954textNode.pivot = { x: 0.2, y: 0.8 } 955textNode.scale = { x: 1, y: 1 } 956 957class MyNodeController extends NodeController { 958 private rootNode: FrameNode | null = null; 959 960 makeNode(uiContext: UIContext): FrameNode { 961 this.rootNode = new FrameNode(uiContext) 962 if (this.rootNode == null) { 963 return this.rootNode 964 } 965 const renderNode = this.rootNode.getRenderNode() 966 if (renderNode != null) { 967 renderNode.frame = { 968 x: 0, 969 y: 0, 970 width: 10, 971 height: 500 972 } 973 renderNode.pivot = { x: 50, y: 50 } 974 } 975 return this.rootNode 976 } 977 978 addNode(node: RenderNode): void { 979 if (this.rootNode == null) { 980 return 981 } 982 const renderNode = this.rootNode.getRenderNode() 983 if (renderNode != null) { 984 renderNode.appendChild(node) 985 } 986 } 987 988 clearNodes(): void { 989 if (this.rootNode == null) { 990 return 991 } 992 const renderNode = this.rootNode.getRenderNode() 993 if (renderNode != null) { 994 renderNode.clearChildren() 995 } 996 } 997} 998 999let myNodeController: MyNodeController = new MyNodeController() 1000 1001async function performTask() { 1002 myNodeController.clearNodes() 1003 myNodeController.addNode(textNode) 1004} 1005 1006@Entry 1007@Component 1008struct Font08 { 1009 @State src: Resource = $r('app.media.startIcon') 1010 build() { 1011 Column() { 1012 Row() { 1013 NodeContainer(myNodeController) 1014 .height('100%') 1015 .width('100%') 1016 Text("Test for vertical alignment") 1017 .onApper(() => { 1018 performTask(); 1019 }) 1020 } 1021 .width('100%') 1022 } 1023 } 1024} 1025``` 1026 1027具体示意效果如下所示: 1028| 样式设置(垂直对齐) | 示意效果 | 1029| -------- | -------- | 1030| 基线对齐(默认)|  | 1031| 顶部对齐 |  | 1032| 居中对齐 |  | 1033| 底部对齐 |  | 1034 1035### 示例四(上下标文本) 1036这里以下标样式为例,呈现上下标文本排版特性。 1037 1038```ts 1039import { NodeController, FrameNode, RenderNode, DrawContext, UIContext } from '@kit.ArkUI' 1040import { drawing, text, common2D } from '@kit.ArkGraphics2D' 1041import { image } from '@kit.ImageKit' 1042 1043// 创建一个MyRenderNode类,并绘制文本。 1044class MyRenderNode extends RenderNode { 1045 async draw(context: DrawContext) { 1046 let canvas = context.canvas; 1047 1048 let myTextStyle: text.TextStyle = { 1049 color: { 1050 alpha: 255, 1051 red: 255, 1052 green: 0, 1053 blue: 0 1054 }, 1055 fontSize: 30, 1056 }; 1057 1058 let subScriptStyle: text.TextStyle = { 1059 color: { 1060 alpha: 255, 1061 red: 255, 1062 green: 0, 1063 blue: 0 1064 }, 1065 fontSize: 30, 1066 // 设置下标样式 1067 badgeType: text.TextBadgeType.TEXT_SUBSCRIPT 1068 }; 1069 1070 let myParagraphStyle: text.ParagraphStyle = { 1071 textStyle: myTextStyle, 1072 }; 1073 1074 let fontCollection = text.FontCollection.getGlobalInstance(); 1075 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 1076 1077 // 设置待排版文本要应用的样式 1078 paragraphBuilder.pushStyle(myTextStyle); 1079 // 添加文本 1080 paragraphBuilder.addText("The chemical formula for water: H"); 1081 paragraphBuilder.pushStyle(subScriptStyle); 1082 paragraphBuilder.addText("2"); 1083 paragraphBuilder.pushStyle(myTextStyle); 1084 paragraphBuilder.addText("o"); 1085 1086 // 生成段落 1087 let paragraph = paragraphBuilder.build(); 1088 // 布局 1089 paragraph.layoutSync(1000); 1090 // 绘制文本 1091 paragraph.paint(canvas, 0, 0); 1092 } 1093} 1094 1095// 创建一个MyRenderNode对象 1096const textNode = new MyRenderNode() 1097// 定义newNode的像素格式 1098textNode.frame = { 1099 x: 0, 1100 y: 0, 1101 width: 400, 1102 height: 600 1103} 1104textNode.pivot = { x: 0.2, y: 0.8 } 1105textNode.scale = { x: 1, y: 1 } 1106 1107class MyNodeController extends NodeController { 1108 private rootNode: FrameNode | null = null; 1109 1110 makeNode(uiContext: UIContext): FrameNode { 1111 this.rootNode = new FrameNode(uiContext) 1112 if (this.rootNode == null) { 1113 return this.rootNode 1114 } 1115 const renderNode = this.rootNode.getRenderNode() 1116 if (renderNode != null) { 1117 renderNode.frame = { 1118 x: 0, 1119 y: 0, 1120 width: 10, 1121 height: 500 1122 } 1123 renderNode.pivot = { x: 50, y: 50 } 1124 } 1125 return this.rootNode 1126 } 1127 1128 addNode(node: RenderNode): void { 1129 if (this.rootNode == null) { 1130 return 1131 } 1132 const renderNode = this.rootNode.getRenderNode() 1133 if (renderNode != null) { 1134 renderNode.appendChild(node) 1135 } 1136 } 1137 1138 clearNodes(): void { 1139 if (this.rootNode == null) { 1140 return 1141 } 1142 const renderNode = this.rootNode.getRenderNode() 1143 if (renderNode != null) { 1144 renderNode.clearChildren() 1145 } 1146 } 1147} 1148 1149let myNodeController: MyNodeController = new MyNodeController() 1150 1151async function performTask() { 1152 myNodeController.clearNodes() 1153 myNodeController.addNode(textNode) 1154} 1155 1156@Entry 1157@Component 1158struct Font08 { 1159 @State src: Resource = $r('app.media.startIcon') 1160 build() { 1161 Column() { 1162 Row() { 1163 NodeContainer(myNodeController) 1164 .height('100%') 1165 .width('100%') 1166 Text("Test for superscript and subscript") 1167 .onApper(() => { 1168 performTask(); 1169 }) 1170 } 1171 } 1172 .width('100%') 1173 } 1174} 1175``` 1176 1177具体示意效果如下所示: 1178| 样式设置(上下标) | 示意效果 | 1179| -------- | -------- | 1180| 上标文本 |  | 1181| 下标文本 |  | 1182 1183### 示例五(高对比度) 1184这里以高对比度为例,呈现高对比度文字的绘制与显示。 1185```ts 1186import { NodeController, FrameNode, RenderNode, DrawContext, UIContext} from '@kit.ArkUI' 1187import { text } from '@kit.ArkGraphics2D' 1188 1189// 创建一个MyRenderNode类,并绘制文本。 1190class MyRenderNode extends RenderNode { 1191 async draw(context: DrawContext) { 1192 let canvas = context.canvas; 1193 1194 // 开启APP的文字渲染高对比度配置 1195 text.setTextHighContrast(text.TextHighContrast.TEXT_APP_ENABLE_HIGH_CONTRAST); 1196 1197 let myTextStyle: text.TextStyle = { 1198 color: { 1199 alpha: 255, 1200 red: 111, 1201 green: 255, 1202 blue: 255 1203 }, 1204 fontSize: 100, 1205 }; 1206 1207 let myParagraphStyle: text.ParagraphStyle = { 1208 textStyle: myTextStyle, 1209 }; 1210 1211 let fontCollection = text.FontCollection.getGlobalInstance(); 1212 let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection); 1213 1214 // 更新文本样式 1215 paragraphBuilder.pushStyle(myTextStyle); 1216 // 添加文本 1217 paragraphBuilder.addText("Hello World"); 1218 1219 // 生成段落 1220 let paragraph = paragraphBuilder.build(); 1221 // 布局 1222 paragraph.layoutSync(1250); 1223 // 绘制文本 1224 paragraph.paint(canvas, 10, 800); 1225 } 1226} 1227 1228// 创建一个MyRenderNode对象 1229const textNode = new MyRenderNode() 1230// 定义newNode的像素格式 1231textNode.frame = { 1232 x: 0, 1233 y: 0, 1234 width: 400, 1235 height: 600 1236} 1237textNode.pivot = { x: 0.2, y: 0.8 } 1238textNode.scale = { x: 1, y: 1 } 1239 1240class MyNodeController extends NodeController { 1241 private rootNode: FrameNode | null = null; 1242 1243 makeNode(uiContext: UIContext): FrameNode { 1244 this.rootNode = new FrameNode(uiContext) 1245 if (this.rootNode == null) { 1246 return this.rootNode 1247 } 1248 const renderNode = this.rootNode.getRenderNode() 1249 if (renderNode != null) { 1250 renderNode.frame = { 1251 x: 0, 1252 y: 0, 1253 width: 10, 1254 height: 500 1255 } 1256 renderNode.pivot = { x: 0.2, y: 0.8 } 1257 } 1258 return this.rootNode 1259 } 1260 1261 addNode(node: RenderNode): void { 1262 if (this.rootNode == null) { 1263 return 1264 } 1265 const renderNode = this.rootNode.getRenderNode() 1266 if (renderNode != null) { 1267 renderNode.appendChild(node) 1268 } 1269 } 1270 1271 clearNodes(): void { 1272 if (this.rootNode == null) { 1273 return 1274 } 1275 const renderNode = this.rootNode.getRenderNode() 1276 if (renderNode != null) { 1277 renderNode.clearChildren() 1278 } 1279 } 1280} 1281 1282let myNodeController: MyNodeController = new MyNodeController() 1283 1284async function performTask() { 1285 myNodeController.clearNodes() 1286 myNodeController.addNode(textNode) 1287} 1288 1289@Entry 1290@Component 1291struct Font08 { 1292 build() { 1293 Column() { 1294 Row() { 1295 NodeContainer(myNodeController) 1296 .height('100%') 1297 .width('100%') 1298 Text("Test high contrast") 1299 .onAppear(() => { 1300 performTask(); 1301 }) 1302 } 1303 .width('100%') 1304 } 1305 } 1306} 1307``` 1308具体示意效果如下所示: 1309 1310| 高对比度设置 | 示意效果 | 1311| -------- | -------- | 1312| 不开启高对比度 |  | 1313| 开启高对比度 |  |