1# BuilderNode
2
3提供能够挂载原生组件的自定义节点BuilderNode。BuilderNode仅可作为叶子节点使用。使用方式参考[BuilderNode开发指南](../../ui/arkts-user-defined-arktsNode-builderNode.md)。
4
5> **说明:**
6>
7> 本模块首批接口从API version 11开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
8>
9> 如果在跨页面复用BuilderNode时显示异常,可参考[跨页面复用注意事项](../../ui/arkts-user-defined-arktsNode-builderNode.md#跨页面复用注意事项)。
10>
11> 当前不支持在预览器中使用BuilderNode。
12
13## 导入模块
14
15```ts
16import { BuilderNode, RenderOptions, NodeRenderType } from "@kit.ArkUI";
17```
18
19## NodeRenderType
20
21节点渲染类型枚举。
22
23**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
24
25**系统能力:** SystemCapability.ArkUI.ArkUI.Full
26
27| 名称                | 值  | 说明                         |
28| ------------------- | --- | ---------------------------- |
29| RENDER_TYPE_DISPLAY | 0   | 表示该节点将被显示到屏幕上。 |
30| RENDER_TYPE_TEXTURE | 1   | 表示该节点将被导出为纹理。   |
31
32> **说明:**
33>
34> RENDER_TYPE_TEXTURE类型目前仅在[BuilderNode](#buildernode-1)持有组件树的根节点为自定义组件时以及[XComponentNode](./js-apis-arkui-xcomponentNode.md)中设置生效。
35>
36> 在[BuilderNode](#buildernode-1)的情况下,目前在作为根节点的自定义组件中支持纹理导出的有以下组件:Badge、Blank、Button、CanvasGradient、CanvasPattern、CanvasRenderingContext2D、Canvas、CheckboxGroup、Checkbox、Circle、ColumnSplit、Column、ContainerSpan、Counter、DataPanel、Divider、Ellipse、Flex、Gauge、Hyperlink、ImageBitmap、ImageData、Image、Line、LoadingProgress、Marquee、Matrix2D、OffscreenCanvasRenderingContext2D、OffscreenCanvas、Path2D、Path、PatternLock、Polygon、Polyline、Progress、QRCode、Radio、Rating、Rect、RelativeContainer、RowSplit、Row、Shape、Slider、Span、Stack、TextArea、TextClock、TextInput、TextTimer、Text、Toggle、Video(不支持原生的全屏模式)、Web、XComponent。
37>
38> 从API version 12开始,新增以下组件支持纹理导出:DatePicker、ForEach、Grid、IfElse、LazyForEach、List、Scroll、Swiper、TimePicker、@Component修饰的自定义组件、NodeContainer以及NodeContainer下挂载的FrameNode和RenderNode。
39>
40> 使用方式可参考[同层渲染绘制](../../web/web-same-layer.md)。
41
42## RenderOptions
43
44创建BuilderNode时的可选参数。
45
46**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
47
48**系统能力:** SystemCapability.ArkUI.ArkUI.Full
49
50| 名称          | 类型                                   | 必填 | 说明                                                         |
51| ------------- | -------------------------------------- | ---- | ------------------------------------------------------------ |
52| selfIdealSize | [Size](js-apis-arkui-graphics.md#size) | 否   | 节点的理想大小。                                             |
53| type          | [NodeRenderType](#noderendertype)      | 否   | 节点的渲染类型。                                             |
54| surfaceId     | string                                 | 否   | 纹理接收方的surfaceId。纹理接收方一般为[OH_NativeImage](../apis-arkgraphics2d/_o_h___native_image.md#oh_nativeimage)。 |
55
56## BuilderNode
57
58class BuilderNode\<Args extends Object[]>
59
60BuilderNode支持通过无状态的UI方法[@Builder](../../quick-start/arkts-builder.md)生成组件树,并持有组件树的根节点。不支持定义为状态变量。BuilderNode中持有的FrameNode仅用于将该BuilderNode作为子节点挂载到其他FrameNode上。对BuilderNode持有的FrameNode进行属性设置与子节点操作可能会产生未定义行为,因此不建议通过BuilderNode的[getFrameNode](#getframenode)方法和[FrameNode](js-apis-arkui-frameNode.md#framenode)的[getRenderNode](js-apis-arkui-frameNode.md#getrendernode)方法获取RenderNode,并通过[RenderNode](js-apis-arkui-renderNode.md#rendernode)的接口对其进行属性设置与子节点操作。
61
62**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
63
64**系统能力:** SystemCapability.ArkUI.ArkUI.Full
65
66### constructor
67
68constructor(uiContext: UIContext, options?: RenderOptions)
69
70当将BuilderNode生成的内容嵌入到其它RenderNode中显示时,即将BuilderNode对应的RenderNode挂载到另一个RenderNode中显示,需要显式指定RenderOptions中的selfIdealSize,否则Builder内的节点默认父组件布局约束为[0,0],即不设置selfIdealSize则认为BuilderNode中子树的根节点大小为[0,0]。
71
72**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
73
74**系统能力:** SystemCapability.ArkUI.ArkUI.Full
75
76| 参数名    | 类型                                    | 必填 | 说明                                                              |
77| --------- | --------------------------------------- | ---- | ----------------------------------------------------------------- |
78| uiContext | [UIContext](js-apis-arkui-UIContext.md) | 是   | UI上下文,获取方式可参考[UIContext获取方法](./js-apis-arkui-node.md#uicontext获取方法)。 |
79| options   | [RenderOptions](#renderoptions)         | 否   | BuilderNode的构造可选参数。默认值:undefined。   |
80
81> **说明**
82> uiContext的入参需要为一个有效的值,即UI上下文正确,如果传入非法值或者未设置,会导致创建失败。
83
84### build
85
86build(builder: WrappedBuilder\<Args>, arg?: Object): void
87
88依照传入的对象创建组件树,并持有组件树的根节点。无状态的UI方法[@Builder](../../quick-start/arkts-builder.md)最多拥有一个根节点。
89支持自定义组件。不支持自定义组件使用[@Reusable](../../quick-start/arkts-create-custom-components.md#自定义组件的基本结构)、[@Link](../../quick-start/arkts-link.md)、[@Provide](../../quick-start/arkts-provide-and-consume.md)、[@Consume](../../quick-start/arkts-provide-and-consume.md)等装饰器,来同步BuilderNode挂载的页面与BuilderNode中自定义组件的状态。
90
91> **说明**
92>
93> @Builder嵌套使用的时候需要保证内外的@Builder方法的入参对象一致。
94>
95> 最外层的@Builder只支持一个入参。
96>
97> 需要操作BuilderNode中的对象时,需要保证其引用不被回收。当BuilderNode对象被虚拟机回收之后,它的FrameNode、RenderNode对象也会与后端节点解引用。即从BuilderNode中获取的FrameNode对象不对应任何一个节点。
98
99**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
100
101**系统能力:** SystemCapability.ArkUI.ArkUI.Full
102
103**参数:**
104
105| 参数名  | 类型                                                            | 必填 | 说明                                                                                   |
106| ------- | --------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------- |
107| builder | [WrappedBuilder\<Args>](../../quick-start/arkts-wrapBuilder.md) | 是   | 创建对应节点树的时候所需的无状态UI方法[@Builder](../../quick-start/arkts-builder.md)。 |
108| arg     | Object                                                          | 否   | builder的入参。当前仅支持一个入参,且入参对象类型与@Builder定义的入参类型保持一致。                                          |
109
110
111### BuildOptions<sup>12+</sup>
112
113build的可选参数。
114
115**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
116
117**系统能力:** SystemCapability.ArkUI.ArkUI.Full
118
119| 名称          | 类型                                   | 必填 | 说明                                                         |
120| ------------- | -------------------------------------- | ---- | ------------------------------------------------------------ |
121| nestingBuilderSupported |boolean | 否   | 是否支持Builder嵌套Builder进行使用。其中,false表示Builder使用的入参一致,true表示Builder使用的入参不一致。默认值:false。                                          |
122
123### build<sup>12+</sup>
124
125build(builder: WrappedBuilder\<Args>, arg: Object, options: [BuildOptions](#buildoptions12)): void
126
127依照传入的对象创建组件树,并持有组件树的根节点。无状态的UI方法[@Builder](../../quick-start/arkts-builder.md)最多拥有一个根节点。
128支持自定义组件。不支持使用自定义组件使用[@Reusable](../../quick-start/arkts-create-custom-components.md#自定义组件的基本结构)、[@Link](../../quick-start/arkts-link.md)、[@Provide](../../quick-start/arkts-provide-and-consume.md)、[@Consume](../../quick-start/arkts-provide-and-consume.md)等装饰器用于当前页面与自定义组件的状态同步。
129
130> **说明**
131>
132> @Builder进行创建和更新的规格参考[@Builder](../../quick-start/arkts-builder.md)。
133>
134> 最外层的@Builder只支持一个入参。
135
136**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
137
138**系统能力:** SystemCapability.ArkUI.ArkUI.Full
139
140**参数:**
141
142| 参数名  | 类型                                                            | 必填 | 说明                                                                                    |
143| ------- | --------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------- |
144| builder | [WrappedBuilder\<Args>](../../quick-start/arkts-wrapBuilder.md) | 是   | 创建对应节点树的时候所需的无状态UI方法[@Builder](../../quick-start/arkts-builder.md)。   |
145| arg     | Object                                                          | 是   | builder的入参。当前仅支持一个入参,且入参对象类型与@Builder定义的入参类型保持一致。                                                            |
146| options | BuildOptions                                                    | 是   | build的配置参数,判断是否支持@Builder中嵌套@Builder的行为。                                         |
147
148**示例:**
149```ts
150import { BuilderNode, NodeContent } from "@kit.ArkUI";
151
152interface ParamsInterface {
153  text: string;
154  func: Function;
155}
156
157@Builder
158function buildTextWithFunc(fun: Function) {
159  Text(fun())
160    .fontSize(50)
161    .fontWeight(FontWeight.Bold)
162    .margin({ bottom: 36 })
163}
164
165@Builder
166function buildText(params: ParamsInterface) {
167  Column() {
168    Text(params.text)
169      .fontSize(50)
170      .fontWeight(FontWeight.Bold)
171      .margin({ bottom: 36 })
172    buildTextWithFunc(params.func)
173  }
174}
175
176
177@Entry
178@Component
179struct Index {
180  @State message: string = "HELLO"
181  private content: NodeContent = new NodeContent();
182
183  build() {
184    Row() {
185      Column() {
186        Button('addBuilderNode')
187          .onClick(() => {
188            let buildNode = new BuilderNode<[ParamsInterface]>(this.getUIContext());
189            buildNode.build(wrapBuilder<[ParamsInterface]>(buildText), {
190              text: this.message, func: () => {
191                return "FUNCTION"
192              }
193            }, { nestingBuilderSupported: true });
194            this.content.addFrameNode(buildNode.getFrameNode());
195            buildNode.dispose();
196          })
197        ContentSlot(this.content)
198      }
199      .id("column")
200      .width('100%')
201      .height('100%')
202    }
203    .height('100%')
204  }
205}
206```
207
208
209### getFrameNode
210
211getFrameNode(): FrameNode | null
212
213获取BuilderNode中的FrameNode。在BuilderNode执行build操作之后,才会生成FrameNode。
214
215**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
216
217**系统能力:** SystemCapability.ArkUI.ArkUI.Full
218
219**返回值:**
220
221| 类型                                                      | 说明                                                                  |
222| --------------------------------------------------------- | --------------------------------------------------------------------- |
223| [FrameNode](js-apis-arkui-frameNode.md#framenode) \| null | 一个FrameNode对象。若该BuilderNode不包含FrameNode,则返回空对象null。 |
224
225**示例1:**
226
227BuilderNode作为NodeContainer的根节点返回。
228
229```ts
230import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI";
231
232class Params {
233  text: string = ""
234  constructor(text: string) {
235    this.text = text;
236  }
237}
238
239@Builder
240function buildText(params: Params) {
241  Column() {
242    Text(params.text)
243      .fontSize(50)
244      .fontWeight(FontWeight.Bold)
245      .margin({bottom: 36})
246  }
247}
248
249class TextNodeController extends NodeController {
250  private textNode: BuilderNode<[Params]> | null = null;
251  private message: string = "DEFAULT";
252
253  constructor(message: string) {
254    super();
255    this.message = message;
256  }
257
258  makeNode(context: UIContext): FrameNode | null {
259    this.textNode = new BuilderNode(context);
260    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message))
261
262    return this.textNode.getFrameNode();
263  }
264}
265
266@Entry
267@Component
268struct Index {
269  @State message: string = "hello"
270
271  build() {
272    Row() {
273      Column() {
274        NodeContainer(new TextNodeController(this.message))
275          .width('100%')
276          .height(100)
277          .backgroundColor('#FFF0F0F0')
278      }
279      .width('100%')
280      .height('100%')
281    }
282    .height('100%')
283  }
284}
285```
286
287**示例2:**
288
289BuilderNode的FrameNode挂到其它FrameNode下。
290
291```ts
292import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI";
293
294class Params {
295  text: string = ""
296
297  constructor(text: string) {
298    this.text = text;
299  }
300}
301
302@Builder
303function buildText(params: Params) {
304  Column() {
305    Text(params.text)
306      .fontSize(50)
307      .fontWeight(FontWeight.Bold)
308      .margin({ bottom: 36 })
309  }
310}
311
312class TextNodeController extends NodeController {
313  private rootNode: FrameNode | null = null;
314  private textNode: BuilderNode<[Params]> | null = null;
315  private message: string = "DEFAULT";
316
317  constructor(message: string) {
318    super();
319    this.message = message;
320  }
321
322  makeNode(context: UIContext): FrameNode | null {
323    this.rootNode = new FrameNode(context);
324    this.textNode = new BuilderNode(context, { selfIdealSize: { width: 150, height: 150 } });
325    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
326    if (this.rootNode !== null) {
327      this.rootNode.appendChild(this.textNode?.getFrameNode());
328    }
329
330    return this.rootNode;
331  }
332}
333
334@Entry
335@Component
336struct Index {
337  @State message: string = "hello"
338
339  build() {
340    Row() {
341      Column() {
342        NodeContainer(new TextNodeController(this.message))
343          .width('100%')
344          .height(100)
345          .backgroundColor('#FFF0F0F0')
346      }
347      .width('100%')
348      .height('100%')
349    }
350    .height('100%')
351  }
352}
353```
354
355**示例3:**
356
357BuilderNode的RenderNode挂到其它RenderNode下。由于RenderNode不传递布局约束,不推荐通过该方式挂载节点。
358
359```ts
360import { NodeController, BuilderNode, FrameNode, UIContext, RenderNode } from "@kit.ArkUI";
361
362class Params {
363  text: string = ""
364
365  constructor(text: string) {
366    this.text = text;
367  }
368}
369
370@Builder
371function buildText(params: Params) {
372  Column() {
373    Text(params.text)
374      .fontSize(50)
375      .fontWeight(FontWeight.Bold)
376      .margin({ bottom: 36 })
377  }
378}
379
380class TextNodeController extends NodeController {
381  private rootNode: FrameNode | null = null;
382  private textNode: BuilderNode<[Params]> | null = null;
383  private message: string = "DEFAULT";
384
385  constructor(message: string) {
386    super();
387    this.message = message;
388  }
389
390  makeNode(context: UIContext): FrameNode | null {
391    this.rootNode = new FrameNode(context);
392    let renderNode = new RenderNode();
393    renderNode.clipToFrame = false;
394    this.textNode = new BuilderNode(context, { selfIdealSize: { width: 150, height: 150 } });
395    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
396    const textRenderNode = this.textNode?.getFrameNode()?.getRenderNode();
397
398    const rootRenderNode = this.rootNode.getRenderNode();
399    if (rootRenderNode !== null) {
400      rootRenderNode.appendChild(renderNode);
401      renderNode.appendChild(textRenderNode);
402    }
403
404    return this.rootNode;
405  }
406}
407
408@Entry
409@Component
410struct Index {
411  @State message: string = "hello"
412
413  build() {
414    Row() {
415      Column() {
416        NodeContainer(new TextNodeController(this.message))
417          .width('100%')
418          .height(100)
419          .backgroundColor('#FFF0F0F0')
420      }
421      .width('100%')
422      .height('100%')
423    }
424    .height('100%')
425  }
426}
427```
428
429### update
430
431update(arg: Object): void
432
433根据提供的参数更新BuilderNode,该参数为[build](#build)方法调用时传入的参数类型相同。对自定义组件进行update的时候需要在自定义组件中使用的变量定义为@Prop类型。
434
435**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
436
437**系统能力:** SystemCapability.ArkUI.ArkUI.Full
438
439**参数:**
440
441| 参数名 | 类型   | 必填 | 说明                                                                     |
442| ------ | ------ | ---- | ------------------------------------------------------------------------ |
443| arg    | Object | 是   | 用于更新BuilderNode的参数,和[build](#build)调用时传入的参数类型一致。 |
444
445**示例:**
446```ts
447import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI";
448
449class Params {
450  text: string = ""
451  constructor(text: string) {
452    this.text = text;
453  }
454}
455
456// 自定义组件
457@Component
458struct TextBuilder {
459  @Prop message: string = "TextBuilder";
460
461  build() {
462    Row() {
463      Column() {
464        Text(this.message)
465          .fontSize(50)
466          .fontWeight(FontWeight.Bold)
467          .margin({bottom: 36})
468          .backgroundColor(Color.Gray)
469      }
470    }
471  }
472}
473
474@Builder
475function buildText(params: Params) {
476  Column() {
477    Text(params.text)
478      .fontSize(50)
479      .fontWeight(FontWeight.Bold)
480      .margin({ bottom: 36 })
481    TextBuilder({message: params.text}) // 自定义组件
482  }
483}
484
485class TextNodeController extends NodeController {
486  private rootNode: FrameNode | null = null;
487  private textNode: BuilderNode<[Params]> | null = null;
488  private message: string = "";
489
490  constructor(message: string) {
491    super()
492    this.message = message
493  }
494
495  makeNode(context: UIContext): FrameNode | null {
496    this.textNode = new BuilderNode(context);
497    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message))
498    return this.textNode.getFrameNode();
499  }
500
501  update(message: string) {
502    if (this.textNode !== null) {
503      this.textNode.update(new Params(message));
504    }
505  }
506}
507
508@Entry
509@Component
510struct Index {
511  @State message: string = "hello"
512  private textNodeController: TextNodeController = new TextNodeController(this.message);
513  private count = 0;
514
515  build() {
516    Row() {
517      Column() {
518        NodeContainer(this.textNodeController)
519          .width('100%')
520          .height(200)
521          .backgroundColor('#FFF0F0F0')
522        Button('Update')
523          .onClick(() => {
524            this.count += 1;
525            const message = "Update " + this.count.toString();
526            this.textNodeController.update(message);
527          })
528      }
529      .width('100%')
530      .height('100%')
531    }
532    .height('100%')
533  }
534}
535```
536
537### postTouchEvent
538
539postTouchEvent(event: TouchEvent): boolean
540
541将原始事件派发到某个BuilderNode创建出的FrameNode上。
542
543postTouchEvent是从组件树的中间节点往下分发,需要变换到父组件坐标系才能分发成功,参考下图。
544
545OffsetA为buildNode相对于父组件的偏移量,可以通过FrameNode中的[getPositionToParent](js-apis-arkui-frameNode.md#getpositiontoparent12)获取。OffsetB为point点相对于buildNode的偏移量,可以通过[TouchEvent](arkui-ts/ts-universal-events-touch.md#touchevent对象说明) 获取。OffsetC为OffsetA与OffsetB的和,是传给postTouchEvent的最终结果。
546
547![postTouchEvent](figures/postTouchEvent.PNG)
548
549> **说明:**
550>
551> 传入的坐标值需要转换为px,如果builderNode有仿射变换,则需要再叠加仿射变换。
552>
553> 在[webview](../apis-arkweb/js-apis-webview.md)中,内部已经处理过坐标系变换,可以将TouchEvent事件直接下发。
554>
555> 同一时间戳,postTouchEvent只能调用一次。<!--Del-->
556>
557> 不支持[UIExtensionComponent](arkui-ts/ts-container-ui-extension-component-sys.md)。
558<!--DelEnd-->
559
560**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
561
562**系统能力:** SystemCapability.ArkUI.ArkUI.Full
563
564**参数:**
565
566| 参数名 | 类型                                                                      | 必填 | 说明       |
567| ------ | ------------------------------------------------------------------------- | ---- | ---------- |
568| event  | [TouchEvent](arkui-ts/ts-universal-events-touch.md#touchevent对象说明) | 是   | 触摸事件。 |
569
570**返回值:**
571
572| 类型    | 说明               |
573| ------- | ------------------ |
574| boolean | 派发事件是否成功。true为已命中响应事件的组件,false为未命中任何可响应事件的组件。<br/>**说明:** <br/>如果未按照预期命中组件,需要确认以下几点:<br/>1.坐标系是否转换正确。<br/>2.组件是否可交互状态。<br/>3.是否绑定事件。 |
575
576**示例:**
577
578```ts
579import { NodeController, BuilderNode, FrameNode, UIContext } from '@kit.ArkUI';
580
581class Params {
582  text: string = "this is a text"
583}
584
585@Builder
586function ButtonBuilder(params: Params) {
587  Column() {
588    Button(`button ` + params.text)
589      .borderWidth(2)
590      .backgroundColor(Color.Orange)
591      .width("100%")
592      .height("100%")
593      .gesture(
594        TapGesture()
595          .onAction((event: GestureEvent) => {
596            console.log("TapGesture");
597          })
598      )
599  }
600  .width(500)
601  .height(300)
602  .backgroundColor(Color.Gray)
603}
604
605class MyNodeController extends NodeController {
606  private rootNode: BuilderNode<[Params]> | null = null;
607  private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(ButtonBuilder);
608
609  makeNode(uiContext: UIContext): FrameNode | null {
610    this.rootNode = new BuilderNode(uiContext);
611    this.rootNode.build(this.wrapBuilder, { text: "this is a string" })
612    return this.rootNode.getFrameNode();
613  }
614
615  // 坐标转换示例
616  postTouchEvent(event: TouchEvent): boolean {
617    if (this.rootNode == null) {
618      return false;
619    }
620    let node: FrameNode | null = this.rootNode.getFrameNode();
621    let offsetX: number | null | undefined = node?.getPositionToParent().x;
622    let offsetY: number | null | undefined = node?.getPositionToParent().y;
623    ;
624    let changedTouchLen = event.changedTouches.length;
625    for (let i = 0; i < changedTouchLen; i++) {
626      if (offsetX != null && offsetY != null && offsetX != undefined && offsetY != undefined) {
627        event.changedTouches[i].x = vp2px(offsetX + event.changedTouches[i].x);
628        event.changedTouches[i].y = vp2px(offsetY + event.changedTouches[i].y);
629      }
630    }
631    let result = this.rootNode.postTouchEvent(event);
632    console.log("result " + result);
633    return result;
634  }
635}
636
637@Entry
638@Component
639struct MyComponent {
640  private nodeController: MyNodeController = new MyNodeController();
641
642  build() {
643    Column() {
644      NodeContainer(this.nodeController)
645        .height(300)
646        .width(500)
647
648      Column()
649        .width(500)
650        .height(300)
651        .backgroundColor(Color.Pink)
652        .onTouch((event) => {
653          if (event != undefined) {
654            this.nodeController.postTouchEvent(event);
655          }
656        })
657    }
658  }
659}
660```
661
662### dispose<sup>12+</sup>
663
664dispose(): void
665
666立即释放当前BuilderNode。当BuilderNode对象调用dispose接口之后,不仅BuilderNode对象与后端实体节点解除引用关系,BuilderNode中的FrameNode与RenderNode也会同步和实体节点解除引用关系。
667
668**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
669
670**系统能力:** SystemCapability.ArkUI.ArkUI.Full
671
672```ts
673import { RenderNode, FrameNode, NodeController, BuilderNode } from "@kit.ArkUI";
674
675@Component
676struct TestComponent {
677  build() {
678    Column() {
679      Text('This is a BuilderNode.')
680        .fontSize(16)
681        .fontWeight(FontWeight.Bold)
682    }
683    .width('100%')
684    .backgroundColor(Color.Gray)
685  }
686
687  aboutToAppear() {
688    console.error('aboutToAppear');
689  }
690
691  aboutToDisappear() {
692    console.error('aboutToDisappear');
693  }
694}
695
696@Builder
697function buildComponent() {
698  TestComponent()
699}
700
701class MyNodeController extends NodeController {
702  private rootNode: FrameNode | null = null;
703  private builderNode: BuilderNode<[]> | null = null;
704
705  makeNode(uiContext: UIContext): FrameNode | null {
706    this.rootNode = new FrameNode(uiContext);
707    this.builderNode = new BuilderNode(uiContext, { selfIdealSize: { width: 200, height: 100 } });
708    this.builderNode.build(new WrappedBuilder(buildComponent));
709
710    const rootRenderNode = this.rootNode!.getRenderNode();
711    if (rootRenderNode !== null) {
712      rootRenderNode.size = { width: 200, height: 200 };
713      rootRenderNode.backgroundColor = 0xff00ff00;
714      rootRenderNode.appendChild(this.builderNode!.getFrameNode()!.getRenderNode());
715    }
716
717    return this.rootNode;
718  }
719
720  dispose() {
721    if (this.builderNode !== null) {
722      this.builderNode.dispose();
723    }
724  }
725
726  removeBuilderNode() {
727    const rootRenderNode = this.rootNode!.getRenderNode();
728    if (rootRenderNode !== null && this.builderNode !== null && this.builderNode.getFrameNode() !== null) {
729      rootRenderNode.removeChild(this.builderNode!.getFrameNode()!.getRenderNode());
730    }
731  }
732}
733
734@Entry
735@Component
736struct Index {
737  private myNodeController: MyNodeController = new MyNodeController();
738
739  build() {
740    Column({ space: 4 }) {
741      NodeContainer(this.myNodeController)
742      Button('BuilderNode dispose')
743        .onClick(() => {
744          this.myNodeController.removeBuilderNode();
745          this.myNodeController.dispose();
746        })
747        .width('100%')
748    }
749  }
750}
751```
752
753### reuse<sup>12+</sup>
754
755reuse(param?: Object): void
756
757传递reuse事件到BuilderNode中的自定义组件。
758
759**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
760
761**系统能力:** SystemCapability.ArkUI.ArkUI.Full
762
763**参数:**
764
765| 参数名 | 类型   | 必填 | 说明                                                                     |
766| ------ | ------ | ---- | ------------------------------------------------------------------------ |
767| param  | Object | 否   | 用于复用BuilderNode的参数,和[build](#build)调用时传入的参数类型一致。 |
768
769### recycle<sup>12+</sup>
770
771recycle(): void
772
773传递recycle事件到BuilderNode中的自定义组件。
774
775**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
776
777**系统能力:** SystemCapability.ArkUI.ArkUI.Full
778
779```ts
780import { FrameNode,NodeController,BuilderNode,UIContext } from "@kit.ArkUI";
781
782class MyDataSource {
783  private dataArray: string[] = [];
784  private listener: DataChangeListener | null = null
785
786  public totalCount(): number {
787    return this.dataArray.length;
788  }
789
790  public getData(index: number) {
791    return this.dataArray[index];
792  }
793
794  public pushData(data: string) {
795    this.dataArray.push(data);
796  }
797
798  public reloadListener(): void {
799    this.listener?.onDataReloaded();
800  }
801
802  public registerDataChangeListener(listener: DataChangeListener): void {
803    this.listener = listener;
804  }
805
806  public unregisterDataChangeListener(): void {
807    this.listener = null;
808  }
809}
810
811class Params {
812  item: string = '';
813
814  constructor(item: string) {
815    this.item = item;
816  }
817}
818
819@Builder
820function buildNode(param: Params = new Params("hello")) {
821  ReusableChildComponent2({ item: param.item });
822}
823
824class MyNodeController extends NodeController {
825  public builderNode: BuilderNode<[Params]> | null = null;
826  public item: string = "";
827
828  makeNode(uiContext: UIContext): FrameNode | null {
829    if (this.builderNode == null) {
830      this.builderNode = new BuilderNode(uiContext, { selfIdealSize: { width: 300, height: 200 } });
831      this.builderNode.build(wrapBuilder<[Params]>(buildNode), new Params(this.item));
832    }
833    return this.builderNode.getFrameNode();
834  }
835}
836
837@Reusable
838@Component
839struct ReusableChildComponent {
840  @State item: string = '';
841  private controller: MyNodeController = new MyNodeController();
842
843  aboutToAppear() {
844    this.controller.item = this.item;
845  }
846
847  aboutToRecycle(): void {
848    console.log("ReusableChildComponent aboutToRecycle " + this.item);
849    this.controller?.builderNode?.recycle();
850  }
851
852  aboutToReuse(params: object): void {
853    console.log("ReusableChildComponent aboutToReuse " + JSON.stringify(params));
854    this.controller?.builderNode?.reuse(params);
855  }
856
857  build() {
858    NodeContainer(this.controller);
859  }
860}
861
862@Component
863struct ReusableChildComponent2 {
864  @Prop item: string = "false";
865
866  aboutToReuse(params: Record<string, object>) {
867    console.log("ReusableChildComponent2 Reusable 2 " + JSON.stringify(params));
868  }
869
870  aboutToRecycle(): void {
871    console.log("ReusableChildComponent2 aboutToRecycle 2 " + this.item);
872  }
873
874  build() {
875    Row() {
876      Text(this.item)
877        .fontSize(20)
878        .backgroundColor(Color.Yellow)
879        .margin({ left: 10 })
880    }.margin({ left: 10, right: 10 })
881  }
882}
883
884
885@Entry
886@Component
887struct Index {
888  @State data: MyDataSource = new MyDataSource();
889
890  aboutToAppear() {
891    for (let i = 0;i < 100; i++) {
892      this.data.pushData(i.toString());
893    }
894  }
895
896  build() {
897    Column() {
898      List({ space: 3 }) {
899        LazyForEach(this.data, (item: string) => {
900          ListItem() {
901            ReusableChildComponent({ item: item })
902          }
903        }, (item: string) => item)
904      }
905      .width('100%')
906      .height('100%')
907    }
908  }
909}
910```
911
912### updateConfiguration<sup>12+</sup>
913
914updateConfiguration(): void
915
916传递[系统环境变化](../apis-ability-kit/js-apis-app-ability-configuration.md)事件,触发节点的全量更新。
917
918**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
919
920**系统能力:** SystemCapability.ArkUI.ArkUI.Full
921
922> **说明:**
923>
924> updateConfiguration接口用于通知对象更新,更新所使用的系统环境由应用当前的系统环境变化决定。
925
926**示例:**
927```ts
928import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI";
929import { AbilityConstant, Configuration, EnvironmentCallback } from '@kit.AbilityKit';
930
931class Params {
932  text: string = ""
933
934  constructor(text: string) {
935    this.text = text;
936  }
937}
938
939// 自定义组件
940@Component
941struct TextBuilder {
942  // 作为自定义组件中需要更新的属性,数据类型为基础属性,定义为@Prop
943  @Prop message: string = "TextBuilder";
944
945  build() {
946    Row() {
947      Column() {
948        Text(this.message)
949          .fontSize(50)
950          .fontWeight(FontWeight.Bold)
951          .margin({ bottom: 36 })
952          .fontColor($r(`app.color.text_color`))
953          .backgroundColor($r(`app.color.start_window_background`))
954      }
955    }
956  }
957}
958
959@Builder
960function buildText(params: Params) {
961  Column() {
962    Text(params.text)
963      .fontSize(50)
964      .fontWeight(FontWeight.Bold)
965      .margin({ bottom: 36 })
966      .fontColor($r(`app.color.text_color`))
967    TextBuilder({ message: params.text }) // 自定义组件
968  }.backgroundColor($r(`app.color.start_window_background`))
969}
970
971class TextNodeController extends NodeController {
972  private textNode: BuilderNode<[Params]> | null = null;
973  private message: string = "";
974
975  constructor(message: string) {
976    super()
977    this.message = message;
978  }
979
980  makeNode(context: UIContext): FrameNode | null {
981    return this.textNode?.getFrameNode() ? this.textNode?.getFrameNode() : null;
982  }
983
984  createNode(context: UIContext) {
985    this.textNode = new BuilderNode(context);
986    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
987    builderNodeMap.push(this.textNode);
988  }
989
990  deleteNode() {
991    let node = builderNodeMap.pop();
992    node?.dispose();
993  }
994
995  update(message: string) {
996    if (this.textNode !== null) {
997      // 调用update进行更新。
998      this.textNode.update(new Params(message));
999    }
1000  }
1001}
1002
1003// 记录创建的自定义节点对象
1004const builderNodeMap: Array<BuilderNode<[Params]>> = new Array();
1005
1006function updateColorMode() {
1007  builderNodeMap.forEach((value, index) => {
1008    // 通知BuilderNode环境变量改变
1009    value.updateConfiguration();
1010  })
1011}
1012
1013@Entry
1014@Component
1015struct Index {
1016  @State message: string = "hello"
1017  private textNodeController: TextNodeController = new TextNodeController(this.message);
1018  private count = 0;
1019
1020  aboutToAppear(): void {
1021    let environmentCallback: EnvironmentCallback = {
1022      onMemoryLevel: (level: AbilityConstant.MemoryLevel): void => {
1023        console.log('onMemoryLevel');
1024      },
1025      onConfigurationUpdated: (config: Configuration): void => {
1026        console.log('onConfigurationUpdated ' + JSON.stringify(config));
1027        updateColorMode();
1028      }
1029    }
1030    // 注册监听回调
1031    this.getUIContext().getHostContext()?.getApplicationContext().on('environment', environmentCallback);
1032    //创建自定义节点并添加至map
1033    this.textNodeController.createNode(this.getUIContext());
1034  }
1035
1036  aboutToDisappear(): void {
1037    //移除map中的引用,并将自定义节点释放
1038    this.textNodeController.deleteNode();
1039  }
1040
1041  build() {
1042    Row() {
1043      Column() {
1044        NodeContainer(this.textNodeController)
1045          .width('100%')
1046          .height(200)
1047          .backgroundColor('#FFF0F0F0')
1048        Button('Update')
1049          .onClick(() => {
1050            this.count += 1;
1051            const message = "Update " + this.count.toString();
1052            this.textNodeController.update(message);
1053          })
1054      }
1055      .width('100%')
1056      .height('100%')
1057    }
1058    .height('100%')
1059  }
1060}
1061```
1062