• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 复杂文本绘制与显示(ArkTS)
2
3在进行文本绘制时,可以通过选择合适的字体、大小和颜色完成简单文本的绘制与显示;此外,还支持通过设置其他丰富的样式、语言、段落等进行复杂文本的绘制。
4
5复杂文本绘制主要包含以下几个场景:
6
7- 多语言文本绘制与显示
8
9- 多行文本绘制与显示
10
11- 多类型文本绘制与显示
12
13
14## 多语言文本绘制与显示
15
16多语言支持是全球化应用的基础。多语言文本绘制需要支持不同语言的字符集及其独特的显示需求,例如右到左语言(如阿拉伯语)或竖排文本(如中文)。开发者需要理解不同语言的渲染特性,确保文本的正确显示。
17
18
19在多语言文本使用的场景下,主要通过指定[TextStyle](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#textstyle)文本样式中的**locale**字段来实现,可直接通过locale字段的值优先匹配对应字体,跳过遍历列表匹配字体的过程,从而降低匹配时间和内存使用。
20
21
22### 开发步骤
23
241. 通过context获取到Canvas画布对象。
25
26   ```ts
27   let canvas = context.canvas;
28   ```
29
302. 初始化文本样式。
31
32   ```ts
33   let myTextStyle: text.TextStyle = {
34     color: {
35       alpha: 255,
36       red: 255,
37       green: 0,
38       blue: 0
39     },
40     fontSize: 50,
41     // 设置语言偏好为简体中文
42     locale: "zh-Hans"
43   };
44   ```
45
463. 初始化段落样式。
47
48   ```ts
49   let myParagraphStyle: text.ParagraphStyle = {
50     textStyle: myTextStyle,
51   };
52   ```
53
544. 初始化段落对象,并添加文本。
55
56   ```ts
57   let fontCollection = text.FontCollection.getGlobalInstance();
58   let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
59   // 更新文本样式
60   ParagraphGraphBuilder.pushStyle(myTextStyle);
61   // 添加文本
62   ParagraphGraphBuilder.addText("你好,世界");
63   ```
64
655. 排版段落并进行文本绘制。
66
67   ```ts
68   // 生成段落
69   let paragraph = ParagraphGraphBuilder.build();
70   // 布局
71   paragraph.layoutSync(1250);
72   // 绘制文本
73   paragraph.paint(canvas, 10, 0);
74   ```
75
76
77### 完整示例
78
79此示例中,要绘制的文本为简体中文,将语言偏好设置为简体中文,在匹配文字字体时,会优先匹配简体,从而提高绘制的效率。
80
81```ts
82import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'
83import { UIContext } from '@kit.ArkUI'
84import { drawing } from '@kit.ArkGraphics2D'
85import { text } from '@kit.ArkGraphics2D'
86import { image } from '@kit.ImageKit'
87import { common2D } from '@kit.ArkGraphics2D'
88
89// 创建一个MyRenderNode类,并绘制文本。
90class MyRenderNode extends RenderNode {
91  async draw(context: DrawContext) {
92    // 绘制代码逻辑写在这里
93    let canvas = context.canvas;
94
95    let myTextStyle: text.TextStyle = {
96      color: {
97        alpha: 255,
98        red: 255,
99        green: 0,
100        blue: 0
101      },
102      fontSize: 50,
103      // 设置语言偏好为简体中文
104      locale: "zh-Hans"
105    };
106
107    let myParagraphStyle: text.ParagraphStyle = {
108      textStyle: myTextStyle,
109    };
110    let fontCollection = text.FontCollection.getGlobalInstance();
111    let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
112    // 更新文本样式
113    ParagraphGraphBuilder.pushStyle(myTextStyle);
114    // 添加文本
115    ParagraphGraphBuilder.addText("你好,世界");
116    // 生成段落
117    let paragraph = ParagraphGraphBuilder.build();
118    // 布局
119    paragraph.layoutSync(1250);
120    // 绘制文本
121    paragraph.paint(canvas, 10, 0);
122  }
123}
124
125// 创建一个MyRenderNode对象
126const textNode = new MyRenderNode()
127// 定义newNode的像素格式
128textNode.frame = {
129  x: 0,
130  y: 100,
131  width: 1250,
132  height: 800
133}
134textNode.pivot = { x: 0.2, y: 0.8 }
135textNode.scale = { x: 1, y: 1 }
136
137class MyNodeController extends NodeController {
138  private rootNode: FrameNode | null = null;
139
140  makeNode(uiContext: UIContext): FrameNode {
141    this.rootNode = new FrameNode(uiContext)
142    if (this.rootNode == null) {
143      return this.rootNode
144    }
145    const renderNode = this.rootNode.getRenderNode()
146    if (renderNode != null) {
147      renderNode.frame = {
148        x: 0,
149        y: 0,
150        width: 10,
151        height: 500
152      }
153      renderNode.pivot = { x: 50, y: 50 }
154    }
155    return this.rootNode
156  }
157
158  addNode(node: RenderNode): void {
159    if (this.rootNode == null) {
160      return
161    }
162    const renderNode = this.rootNode.getRenderNode()
163    if (renderNode != null) {
164      renderNode.appendChild(node)
165    }
166  }
167
168  clearNodes(): void {
169    if (this.rootNode == null) {
170      return
171    }
172    const renderNode = this.rootNode.getRenderNode()
173    if (renderNode != null) {
174      renderNode.clearChildren()
175    }
176  }
177}
178
179let myNodeController: MyNodeController = new MyNodeController()
180
181async function performTask() {
182  myNodeController.clearNodes()
183  myNodeController.addNode(textNode)
184}
185
186@Entry
187@Component
188struct Font08 {
189  @State src: Resource = $r('app.media.startIcon')
190  build() {
191    Column() {
192      Row() {
193        NodeContainer(myNodeController)
194          .height('100%')
195          .width('100%')
196        Image(this.src)
197          .width('0%').height('0%')
198          .onComplete(
199            () => {
200              performTask();
201            })
202      }
203      .width('100%')
204    }
205  }
206}
207```
208
209
210### 效果展示
211
212![zh-cn_image_0000002246603733](figures/zh-cn_image_0000002246603733.png)
213
214
215## 多行文本绘制与显示
216
217多行文本相对于单行文本比较复杂,一般针对多行文本,需要进行文本排版、断词策略设置、文本对齐方式、最大行数限制等,主要通过设置段落样式实现。
218
219
220### 实现说明
221
222**段落样式**([ParagraphStyle](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#paragraphstyle))是对多行文本中每段内容的样式设置,包括断词策略、文本对齐方式、最大行数限制等。开发者可以通过对不同段落进行样式化,以提高文本的可读性和美观性。
223
224
225### 开发步骤
226
2271. 通过context获取到Canvas画布对象。
228
229   ```ts
230   // 绘制代码逻辑写在这里
231   let canvas = context.canvas;
232   ```
233
2342. 初始化文本样式。
235
236   ```ts
237   let myTextStyle: text.TextStyle = {
238     color: {
239       alpha: 255,
240       red: 255,
241       green: 0,
242       blue: 0
243     },
244     fontSize: 50,
245   };
246   ```
247
2483. 初始化段落样式。
249
250   ```ts
251   let myParagraphStyle: text.ParagraphStyle = {
252     textStyle: myTextStyle,
253     // 本文对齐方式
254     align: text.TextAlign.LEFT,
255     // 最大行数
256     maxLines: 3,
257     // 断词策略
258     wordBreak: text.WordBreak.BREAK_WORD
259   };
260   ```
261
2624. 初始化段落对象,并添加占位符和文本。
263
264   ```ts
265   let fontCollection = text.FontCollection.getGlobalInstance();
266   let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
267   // 更新文本样式
268   ParagraphGraphBuilder.pushStyle(myTextStyle);
269   // 添加文本
270   ParagraphGraphBuilder.addText("Hello World Hello World Hello World Hello World Hello World Hello World " +
271     "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World " +
272     "Hello World Hello World Hello World Hello World Hello World ");
273   ```
274
2755. 排版段落并进行文本绘制。
276
277   ```ts
278   // 生成段落
279   let paragraph = ParagraphGraphBuilder.build();
280   // 布局
281   paragraph.layoutSync(1250);
282   // 绘制文本
283   paragraph.paint(canvas, 10, 0);
284   ```
285
286
287### 完整示例
288
289```ts
290import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'
291import { UIContext } from '@kit.ArkUI'
292import { drawing } from '@kit.ArkGraphics2D'
293import { text } from '@kit.ArkGraphics2D'
294import { image } from '@kit.ImageKit'
295import { common2D } from '@kit.ArkGraphics2D'
296
297// 创建一个MyRenderNode类,并绘制文本。
298class MyRenderNode extends RenderNode {
299  async draw(context: DrawContext) {
300    // 绘制代码逻辑写在这里
301    let canvas = context.canvas;
302
303    let myTextStyle: text.TextStyle = {
304      color: {
305        alpha: 255,
306        red: 255,
307        green: 0,
308        blue: 0
309      },
310      fontSize: 50,
311    };
312
313    let myParagraphStyle: text.ParagraphStyle = {
314      textStyle: myTextStyle,
315      // 本文对齐方式
316      align: text.TextAlign.LEFT,
317      // 最大行数
318      maxLines: 3,
319      // 断词策略
320      wordBreak: text.WordBreak.BREAK_WORD
321    };
322    let fontCollection = text.FontCollection.getGlobalInstance();
323    let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
324    // 更新文本样式
325    ParagraphGraphBuilder.pushStyle(myTextStyle);
326    // 添加文本
327    ParagraphGraphBuilder.addText("Hello World Hello World Hello World Hello World Hello World Hello World " +
328      "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World " +
329      "Hello World Hello World Hello World Hello World Hello World ");
330    // 生成段落
331    let paragraph = ParagraphGraphBuilder.build();
332    // 布局
333    paragraph.layoutSync(1250);
334    // 绘制文本
335    paragraph.paint(canvas, 10, 0);
336  }
337}
338
339// 创建一个MyRenderNode对象
340const textNode = new MyRenderNode()
341// 定义newNode的像素格式
342textNode.frame = {
343  x: 0,
344  y: 100,
345  width: 1250,
346  height: 800
347}
348textNode.pivot = { x: 0.2, y: 0.8 }
349textNode.scale = { x: 1, y: 1 }
350
351class MyNodeController extends NodeController {
352  private rootNode: FrameNode | null = null;
353
354  makeNode(uiContext: UIContext): FrameNode {
355    this.rootNode = new FrameNode(uiContext)
356    if (this.rootNode == null) {
357      return this.rootNode
358    }
359    const renderNode = this.rootNode.getRenderNode()
360    if (renderNode != null) {
361      renderNode.frame = {
362        x: 0,
363        y: 0,
364        width: 10,
365        height: 500
366      }
367      renderNode.pivot = { x: 50, y: 50 }
368    }
369    return this.rootNode
370  }
371
372  addNode(node: RenderNode): void {
373    if (this.rootNode == null) {
374      return
375    }
376    const renderNode = this.rootNode.getRenderNode()
377    if (renderNode != null) {
378      renderNode.appendChild(node)
379    }
380  }
381
382  clearNodes(): void {
383    if (this.rootNode == null) {
384      return
385    }
386    const renderNode = this.rootNode.getRenderNode()
387    if (renderNode != null) {
388      renderNode.clearChildren()
389    }
390  }
391}
392
393let myNodeController: MyNodeController = new MyNodeController()
394
395async function performTask() {
396  myNodeController.clearNodes()
397  myNodeController.addNode(textNode)
398}
399
400@Entry
401@Component
402struct Font08 {
403  @State src: Resource = $r('app.media.startIcon')
404  build() {
405    Column() {
406      Row() {
407        NodeContainer(myNodeController)
408          .height('100%')
409          .width('100%')
410        Image(this.src)
411          .width('0%').height('0%')
412          .onComplete(
413            () => {
414              performTask();
415            })
416      }
417      .width('100%')
418    }
419  }
420}
421```
422
423
424### 效果展示
425
426| 段落样式设置(断词策略、文本对齐方式、最大行数限制) | 效果示意 |
427| -------- | -------- |
428| 文本对齐方式为text.TextAlign.LEFT,最大行数为3,断词策略为text.WordBreak.BREAK_WORD。 | ![zh-cn_image_0000002246563849](figures/zh-cn_image_0000002246563849.png) |
429| 文本对齐方式为text.TextAlign.RIGHT,最大行数为3,断词策略为text.WordBreak.BREAK_WORD。 | ![zh-cn_image_0000002211443900](figures/zh-cn_image_0000002211443900.png) |
430| 文本对齐方式为text.TextAlign.LEFT,最大行数为3,断词策略为text.WordBreak.BREAK_ALL。 | ![zh-cn_image_0000002211603680](figures/zh-cn_image_0000002211603680.png) |
431| 文本对齐方式为text.TextAlign.LEFT ,最大行数为10 ,断词策略为text.WordBreak.BREAK_ALL。 | ![zh-cn_image_0000002246563845](figures/zh-cn_image_0000002246563845.png) |
432
433
434## 多样式文本绘制与显示
435
436除基本文字、排版属性之外,针对应用中不同文本的设计,开发者可能需要设置使用不同的绘制样式或能力,以凸显对应文本的独特表现或风格,此时可以结合使用多种绘制样式进行文本的渲染。
437
438当前支持的多样式绘制及各绘制样式侧重效果如下:
439
440- **装饰线样式绘制:** 主要通过不同的线条样式对文本进行装饰,可以使文本更加突出,富有表现力。
441
442- **字体特性绘制:** 主要通过字体的变化,包括粗细、斜体等特性来改变文本的外观,增强文本的可读性和美观性。
443
444- **可变字体绘制:** 对应提供文本在不同的显示环境和设备上灵活灵活调整的能力,可满足更为精细的视觉效果。
445
446- **文本阴影绘制:** 主要通过在文本周围添加阴影效果,以提升文本的层次感和立体感,从而使文本更具吸引力。
447
448- **占位符绘制:** 可以在不确定文本内容时保持文本布局的稳定性,使得文本显示更为流畅和自然。
449
450### 装饰线
451
452装饰线([Decoration](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#decoration))是指在文本上方、下方或中间添加的装饰性线条,当前支持上划线、下划线、删除线。
453
454可以通过添加文本装饰线,提升文本的视觉效果和可读性。
455
456使用装饰线需要初始化装饰线样式对象,并添加到文本样式中,从而在文本绘制时生效。
457
458### 字体特征
459
460**字体特征**([FontFeature](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#fontfeature))绘制专注于在文本渲染过程中对字体特性(如粗体、斜体、字体变种等)的处理,允许字体在不同的排版场景下表现出不同的效果,可用于增强文本的表现力,使其更符合设计和阅读需求。
461
462常见的**FontFeature**包含有liga、frac、case等,需要对应的ttf文件支持才能正常使能。
463
464### 可变字体
465
466**可变字体**([FontVariation](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#fontvariation))是一种在一个字体文件中包含多个字形变体的字体格式,允许在一个字体文件内灵活地调整字体的各种属性(如字重、字宽、斜体等)。
467
468与传统字体文件(每种变体需要一个独立的文件)不同,可变字体在一个字体文件中包含多个变体轴,可通过使用可变字体实现文本渲染绘制时的平滑过渡。
469
470### 文本阴影
471
472**文本阴影**([TextShadow](../reference/apis-arkgraphics2d/js-apis-graphics-text.md#textshadow))为文本提供了深度感,使得文本在背景上更具立体感。通常用于提升文本的视觉吸引力或增强可读性,尤其是在色彩对比度较低的场景下。
473
474其中,TesxtShadow有三个属性,分别为阴影颜色color、阴影基于当前文本的偏移位置point、阴影半径blurRadius。
475
476使用阴影效果需要在文本样式中设置对应的阴影效果数组,从而在文本绘制时生效。
477
478### 占位符
479
480占位符绘制用于处理文本中占位符符号的渲染。
481
482占位符也是用来实现图文混排的关键,是指在实际图像或内容注册之前,用来预先提供货替代某个位置的视觉元素。
483
484### 开发步骤
485
4861. 通过context获取到Canvas画布对象。
487
488   ```ts
489   // 绘制代码逻辑写在这里
490   let canvas = context.canvas;
491   ```
492
4932. 初始化文本样式。
494
495   ```ts
496   // 初始化装饰线对象
497   let decorations: text.Decoration =
498     {
499       // 装饰线类型,支持上划线、下划线、删除线
500       textDecoration: text.TextDecorationType.UNDERLINE,
501       // 装饰线颜色
502       color: {
503         alpha: 255,
504         red: 255,
505         green: 0,
506         blue: 0
507       },
508       // 装饰线样式,支持波浪,虚线,直线等
509       decorationStyle:text.TextDecorationStyle.SOLID,
510       // 装饰线的高度
511       decorationThicknessScale: 1
512     };
513
514   let myTextStyle: text.TextStyle = {
515     color: {
516       alpha: 255,
517       red: 255,
518       green: 0,
519       blue: 0
520     },
521     fontSize: 300,
522     // 设置装饰线
523     decoration: decorations,
524     // 可变字体
525     fontVariations: [{axis: 'wght', value: 555}],
526     // 文本阴影
527     textShadows: [{color: { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }, point: {x:10,y:10}, blurRadius: 10}],
528     // 开启字体特征
529     fontFeatures: [{name: 'frac', value: 1}]
530   };
531   ```
532
5333. 初始化段落样式。
534
535   ```ts
536   let myParagraphStyle: text.ParagraphStyle = {
537     textStyle: myTextStyle
538   };
539   ```
540
5414. 初始化段落对象,并添加占位符和文本。
542
543   ```ts
544   let fontCollection = text.FontCollection.getGlobalInstance();
545   let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
546
547   // 初始化占位符对象
548   let myPlaceholderSpan: text.PlaceholderSpan = {
549     width: 300,//宽度
550     height: 300,//高度
551     align: text.PlaceholderAlignment.BOTTOM_OF_ROW_BOX, //基线对齐策略
552     baseline: text.TextBaseline.ALPHABETIC,//使用的文本基线类型
553     baselineOffset: 100//相比基线的偏移量。只有对齐策略是OFFSET_AT_BASELINE时生效
554   };
555   // 添加占位符
556   ParagraphGraphBuilder.addPlaceholder(myPlaceholderSpan)
557
558   // 更新文本样式
559   ParagraphGraphBuilder.pushStyle(myTextStyle);
560   // 添加文本
561   ParagraphGraphBuilder.addText("1/2 1/3 1/4 ");
562   ```
563
5645. 排版段落并进行文本绘制。
565
566   ```ts
567   //生成段落
568   let paragraph = ParagraphGraphBuilder.build();
569   // 布局
570   paragraph.layoutSync(1250);
571   // 绘制文本
572   paragraph.paint(canvas, 0, 0);
573   ```
574
5756. 绘制占位符所在的内容。
576
577   ```ts
578   let placeholderRects = paragraph.getRectsForPlaceholders();//获取全部占位符的数组
579   let left = placeholderRects[0].rect.left//获取第一个占位符的左边界
580   let top = placeholderRects[0].rect.top//获取第一个占位符的上边界
581   let right = placeholderRects[0].rect.right//获取第一个占位符的有边界
582   let bottom = placeholderRects[0].rect.bottom//获取第一个占位符的下边界
583   let pen: drawing.Pen =  new drawing.Pen()
584   let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }
585   pen.setColor(pen_color)
586   canvas.attachPen(pen)
587   canvas.drawRect(left,top,right,bottom)//使用draw方法绘制占位符矩形框
588   ```
589
590
591### 完整示例
592
593```ts
594import { NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'
595import { UIContext } from '@kit.ArkUI'
596import { drawing } from '@kit.ArkGraphics2D'
597import { text } from '@kit.ArkGraphics2D'
598import { image } from '@kit.ImageKit'
599import { common2D } from '@kit.ArkGraphics2D'
600
601// 创建一个MyRenderNode类,并绘制文本。
602class MyRenderNode extends RenderNode {
603  async draw(context: DrawContext) {
604    // 绘制代码逻辑写在这里
605    let canvas = context.canvas;
606
607    // 初始化装饰线对象
608    let decorations: text.Decoration =
609      {
610        // 装饰线类型,支持上划线、下划线、删除线
611        textDecoration: text.TextDecorationType.UNDERLINE,
612        // 装饰线颜色
613        color: {
614          alpha: 255,
615          red: 255,
616          green: 0,
617          blue: 0
618        },
619        // 装饰线样式,支持波浪,虚线,直线等
620        decorationStyle:text.TextDecorationStyle.SOLID,
621        // 装饰线的高度
622        decorationThicknessScale: 1
623      };
624
625    let myTextStyle: text.TextStyle = {
626      color: {
627        alpha: 255,
628        red: 255,
629        green: 0,
630        blue: 0
631      },
632      fontSize: 300,
633      // 设置装饰线
634      decoration: decorations,
635      // 可变字体
636      fontVariations: [{axis: 'wght', value: 555}],
637      // 文本阴影
638      textShadows: [{color: { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }, point: {x:10,y:10}, blurRadius: 10}],
639      // 开启字体特征
640      fontFeatures: [{name: 'frac', value: 1}]
641    };
642
643    let myParagraphStyle: text.ParagraphStyle = {
644      textStyle: myTextStyle
645    };
646
647    let fontCollection = text.FontCollection.getGlobalInstance();
648    let ParagraphGraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
649
650    // 初始化占位符对象
651    let myPlaceholderSpan: text.PlaceholderSpan = {
652      width: 300,//宽度
653      height: 300,//高度
654      align: text.PlaceholderAlignment.BOTTOM_OF_ROW_BOX, //基线对齐策略
655      baseline: text.TextBaseline.ALPHABETIC,//使用的文本基线类型
656      baselineOffset: 100//相比基线的偏移量。只有对齐策略是OFFSET_AT_BASELINE时生效
657    };
658    // 添加占位符
659    ParagraphGraphBuilder.addPlaceholder(myPlaceholderSpan)
660
661    // 更新文本样式
662    ParagraphGraphBuilder.pushStyle(myTextStyle);
663    // 添加文本
664    ParagraphGraphBuilder.addText("1/2 1/3 1/4 ");
665
666    // 生成段落
667    let paragraph = ParagraphGraphBuilder.build();
668    // 布局
669    paragraph.layoutSync(1250);
670    // 绘制文本
671    paragraph.paint(canvas, 0, 0);
672
673    let placeholderRects = paragraph.getRectsForPlaceholders();//获取全部占位符的数组
674    let left = placeholderRects[0].rect.left// 获取第一个占位符的左边界
675    let top = placeholderRects[0].rect.top// 获取第一个占位符的上边界
676    let right = placeholderRects[0].rect.right// 获取第一个占位符的有边界
677    let bottom = placeholderRects[0].rect.bottom// 获取第一个占位符的下边界
678    let pen: drawing.Pen =  new drawing.Pen()
679    let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }
680    pen.setColor(pen_color)
681    canvas.attachPen(pen)
682    canvas.drawRect(left,top,right,bottom)// 使用draw方法绘制占位符矩形框
683  }
684}
685
686// 创建一个MyRenderNode对象
687const textNode = new MyRenderNode()
688// 定义newNode的像素格式
689textNode.frame = {
690  x: 0,
691  y: 100,
692  width: 1250,
693  height: 800
694}
695textNode.pivot = { x: 0.2, y: 0.8 }
696textNode.scale = { x: 1, y: 1 }
697
698class MyNodeController extends NodeController {
699  private rootNode: FrameNode | null = null;
700
701  makeNode(uiContext: UIContext): FrameNode {
702    this.rootNode = new FrameNode(uiContext)
703    if (this.rootNode == null) {
704      return this.rootNode
705    }
706    const renderNode = this.rootNode.getRenderNode()
707    if (renderNode != null) {
708      renderNode.frame = {
709        x: 0,
710        y: 0,
711        width: 10,
712        height: 500
713      }
714      renderNode.pivot = { x: 50, y: 50 }
715    }
716    return this.rootNode
717  }
718
719  addNode(node: RenderNode): void {
720    if (this.rootNode == null) {
721      return
722    }
723    const renderNode = this.rootNode.getRenderNode()
724    if (renderNode != null) {
725      renderNode.appendChild(node)
726    }
727  }
728
729  clearNodes(): void {
730    if (this.rootNode == null) {
731      return
732    }
733    const renderNode = this.rootNode.getRenderNode()
734    if (renderNode != null) {
735      renderNode.clearChildren()
736    }
737  }
738}
739
740let myNodeController: MyNodeController = new MyNodeController()
741
742async function performTask() {
743  myNodeController.clearNodes()
744  myNodeController.addNode(textNode)
745}
746
747@Entry
748@Component
749struct Font08 {
750  @State src: Resource = $r('app.media.startIcon')
751  build() {
752    Column() {
753      Row() {
754        NodeContainer(myNodeController)
755          .height('100%')
756          .width('100%')
757        Image(this.src)
758          .width('0%').height('0%')
759          .onComplete(
760            () => {
761              performTask();
762            })
763      }
764      .width('100%')
765    }
766  }
767}
768```
769
770
771### 效果展示
772
773| 样式设置(装饰线样式、可变字体、文本阴影、字体特征、占位符) | 示意效果 |
774| -------- | -------- |
775| 不开启装饰线、可变字体、文本阴影、字体特征,不添加占位符。 | ![zh-cn_image_0000002211603688](figures/zh-cn_image_0000002211603688.png) |
776| 开启装饰线、可变字体、文本阴影、字体特征,添加占位符。 | ![zh-cn_image_0000002211443912](figures/zh-cn_image_0000002211443912.png) |
777