1e41f4b71Sopenharmony_ci# FrameNode
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciFor third-party frameworks with custom frontend definitions, converting specific DSL to ArkUI declarative descriptions is required. This process, which relies on additional data-driven bindings to the [Builder](../quick-start/arkts-builder.md), is complex and can be performance-intensive. Such frameworks typically leverage ArkUI's layout and event handling, as well as basic node operations and customization capabilities. While most components are customized, some built-in components are needed for mixed display. This is where [FrameNode](../reference/apis-arkui/js-apis-arkui-frameNode.md) comes into the picture.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciFrameNode represents an entity node in the component tree. When used with custom placeholder containers such as [NodeContainer](../reference/apis-arkui/arkui-ts/ts-basic-components-nodecontainer.md), it allows for mounting and dynamically managing a custom node tree in the containers, including node addition, modification, and removal. Basic FrameNodes enable universal attribute setting, event callback setting, and full customization for measurement, layout, and rendering.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciMoreover, the ArkUI framework enables obtaining and traversing proxy FrameNode objects for built-in components, known as proxy nodes, which facilitate UI tree traversal and allow for obtaining specific information about built-in components or registering additional event listeners.
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci## Creating and Removing Nodes
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciYou can create and remove nodes with **FrameNode**. You can create a custom instance of **FrameNode** using its constructor, and the instance thereby created corresponds to an entity node. You can use the [dispose](../reference/apis-arkui/js-apis-arkui-frameNode.md#dispose12) API in **FrameNode** to break the binding with the entity node.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci> **NOTE**
16e41f4b71Sopenharmony_ci>
17e41f4b71Sopenharmony_ci> - A valid **UIContext** object is required for creating a FrameNode. If no **UIContext** object is provided or if the provided one is invalid, an exception will be thrown during node creation.
18e41f4b71Sopenharmony_ci>
19e41f4b71Sopenharmony_ci> - Maintain UI context consistency for custom placeholder components to prevent display issues.
20e41f4b71Sopenharmony_ci>
21e41f4b71Sopenharmony_ci> - **FrameNode** objects are subject to garbage collection (GC) if not retained.
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci## Checking Whether a Node is Modifiable
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ciUse [isModifiable](../reference/apis-arkui/js-apis-arkui-frameNode.md#ismodifiable12) to check whether the current node is a proxy for a built-in component. If a FrameNode serves as a proxy, it cannot be modified, which means you cannot change its properties or the structure of its child nodes.
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci## Obtaining the Corresponding RenderNode
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ciUse the [getRenderNode](../reference/apis-arkui/js-apis-arkui-frameNode.md#getrendernode) API to obtain the RenderNode associated with the FrameNode. You can then perform operations on the obtained RenderNode object to dynamically modify the drawing-related properties of the FrameNode. For details about the properties that can be modified, see the RenderNode API documentation.
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci> **NOTE**
32e41f4b71Sopenharmony_ci>
33e41f4b71Sopenharmony_ci> - You cannot obtain the RenderNode for a built-in component's proxy FrameNode.
34e41f4b71Sopenharmony_ci> 
35e41f4b71Sopenharmony_ci> - In **BuilderNode**, you can use [getFrameNode](../reference/apis-arkui/js-apis-arkui-builderNode.md#getframenode) to get the FrameNode object, and then use **getRenderNode** to obtain the RenderNode object of the corresponding root node.
36e41f4b71Sopenharmony_ci
37e41f4b71Sopenharmony_ci## Operating the Node Tree
38e41f4b71Sopenharmony_ci
39e41f4b71Sopenharmony_ciWith **FrameNode**, you can add, delete, query, and modify nodes, thereby changing the subtree structure of non-proxy nodes; you can also query the parent-child relationships to obtain the results.
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci> **NOTE**
42e41f4b71Sopenharmony_ci>
43e41f4b71Sopenharmony_ci> Illegal operations for adding, deleting, or modifying nodes result in exceptions.
44e41f4b71Sopenharmony_ci>
45e41f4b71Sopenharmony_ci> Proxy nodes obtained through queries can only be used to obtain node information and cannot modify node properties; they do not hold the component entity nodes, meaning they do not affect the lifecycle of the corresponding nodes.
46e41f4b71Sopenharmony_ci>
47e41f4b71Sopenharmony_ci> Node queries only return UI-related nodes and do not include syntax nodes.
48e41f4b71Sopenharmony_ci>
49e41f4b71Sopenharmony_ci> In scenarios using custom components, you may query and obtain newly added nodes of the custom components, with the node type being **__Common__**.
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ci```ts
52e41f4b71Sopenharmony_ciimport { BuilderNode, FrameNode, NodeController, UIContext } from '@kit.ArkUI';
53e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit';
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ciconst TEST_TAG: string = "FrameNode"
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ciclass Params {
58e41f4b71Sopenharmony_ci  text: string = "this is a text"
59e41f4b71Sopenharmony_ci}
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci@Builder
62e41f4b71Sopenharmony_cifunction buttonBuilder(params: Params) {
63e41f4b71Sopenharmony_ci  Column({ space: 10 }) {
64e41f4b71Sopenharmony_ci    Button(params.text)
65e41f4b71Sopenharmony_ci      .fontSize(12)
66e41f4b71Sopenharmony_ci      .borderRadius(8)
67e41f4b71Sopenharmony_ci      .borderWidth(2)
68e41f4b71Sopenharmony_ci      .backgroundColor(Color.Orange)
69e41f4b71Sopenharmony_ci
70e41f4b71Sopenharmony_ci    Button(params.text)
71e41f4b71Sopenharmony_ci      .fontSize(12)
72e41f4b71Sopenharmony_ci      .borderRadius(8)
73e41f4b71Sopenharmony_ci      .borderWidth(2)
74e41f4b71Sopenharmony_ci      .backgroundColor(Color.Pink)
75e41f4b71Sopenharmony_ci  }
76e41f4b71Sopenharmony_ci}
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ciclass MyNodeController extends NodeController {
79e41f4b71Sopenharmony_ci  public buttonNode: BuilderNode<[Params]> | null = null;
80e41f4b71Sopenharmony_ci  public frameNode: FrameNode | null = null;
81e41f4b71Sopenharmony_ci  public childList: Array<FrameNode> = new Array<FrameNode>();
82e41f4b71Sopenharmony_ci  public rootNode: FrameNode | null = null;
83e41f4b71Sopenharmony_ci  private uiContext: UIContext | null = null;
84e41f4b71Sopenharmony_ci  private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(buttonBuilder);
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ci  makeNode(uiContext: UIContext): FrameNode | null {
87e41f4b71Sopenharmony_ci    this.uiContext = uiContext;
88e41f4b71Sopenharmony_ci    if (this.rootNode == null) {
89e41f4b71Sopenharmony_ci      this.rootNode = new FrameNode(uiContext);
90e41f4b71Sopenharmony_ci      this.rootNode.commonAttribute
91e41f4b71Sopenharmony_ci        .width("50%")
92e41f4b71Sopenharmony_ci        .height(100)
93e41f4b71Sopenharmony_ci        .borderWidth(1)
94e41f4b71Sopenharmony_ci        .backgroundColor(Color.Gray)
95e41f4b71Sopenharmony_ci    }
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci    if (this.frameNode == null) {
98e41f4b71Sopenharmony_ci      this.frameNode = new FrameNode(uiContext);
99e41f4b71Sopenharmony_ci      this.frameNode.commonAttribute
100e41f4b71Sopenharmony_ci        .width("100%")
101e41f4b71Sopenharmony_ci        .height(50)
102e41f4b71Sopenharmony_ci        .borderWidth(1)
103e41f4b71Sopenharmony_ci        .position({ x: 200, y: 0 })
104e41f4b71Sopenharmony_ci        .backgroundColor(Color.Pink);
105e41f4b71Sopenharmony_ci      this.rootNode.appendChild(this.frameNode);
106e41f4b71Sopenharmony_ci    }
107e41f4b71Sopenharmony_ci    if (this.buttonNode == null) {
108e41f4b71Sopenharmony_ci      this.buttonNode = new BuilderNode<[Params]>(uiContext);
109e41f4b71Sopenharmony_ci      this.buttonNode.build(this.wrapBuilder, { text: "This is a Button" })
110e41f4b71Sopenharmony_ci      this.rootNode.appendChild(this.buttonNode.getFrameNode())
111e41f4b71Sopenharmony_ci    }
112e41f4b71Sopenharmony_ci    return this.rootNode;
113e41f4b71Sopenharmony_ci  }
114e41f4b71Sopenharmony_ci
115e41f4b71Sopenharmony_ci  operationFrameNodeWithFrameNode(frameNode: FrameNode | undefined | null) {
116e41f4b71Sopenharmony_ci    if (frameNode) {
117e41f4b71Sopenharmony_ci      console.log(TEST_TAG + " get ArkTSNode success.")
118e41f4b71Sopenharmony_ci      console.log(TEST_TAG + " check rootNode whether is modifiable " + frameNode.isModifiable());
119e41f4b71Sopenharmony_ci    }
120e41f4b71Sopenharmony_ci    if (this.uiContext) {
121e41f4b71Sopenharmony_ci      let frameNode1 = new FrameNode(this.uiContext);
122e41f4b71Sopenharmony_ci      let frameNode2 = new FrameNode(this.uiContext);
123e41f4b71Sopenharmony_ci      frameNode1.commonAttribute.size({ width: 50, height: 50 })
124e41f4b71Sopenharmony_ci        .backgroundColor(Color.Black)
125e41f4b71Sopenharmony_ci        .position({ x: 50, y: 60 })
126e41f4b71Sopenharmony_ci      frameNode2.commonAttribute.size({ width: 50, height: 50 })
127e41f4b71Sopenharmony_ci        .backgroundColor(Color.Orange)
128e41f4b71Sopenharmony_ci        .position({ x: 120, y: 60 })
129e41f4b71Sopenharmony_ci      try {
130e41f4b71Sopenharmony_ci        frameNode?.appendChild(frameNode1);
131e41f4b71Sopenharmony_ci        console.log(TEST_TAG + " appendChild success ");
132e41f4b71Sopenharmony_ci      } catch (err) {
133e41f4b71Sopenharmony_ci        console.log(TEST_TAG + " appendChild fail :" + (err as BusinessError).code + " : " + (err as BusinessError).message);
134e41f4b71Sopenharmony_ci      }
135e41f4b71Sopenharmony_ci      try {
136e41f4b71Sopenharmony_ci        frameNode?.insertChildAfter(frameNode2, null);
137e41f4b71Sopenharmony_ci        console.log(TEST_TAG + " insertChildAfter success ");
138e41f4b71Sopenharmony_ci      } catch (err) {
139e41f4b71Sopenharmony_ci        console.log(TEST_TAG + " insertChildAfter fail : " + (err as BusinessError).code + " : " + (err as BusinessError).message);
140e41f4b71Sopenharmony_ci      }
141e41f4b71Sopenharmony_ci      setTimeout(() => {
142e41f4b71Sopenharmony_ci        try {
143e41f4b71Sopenharmony_ci          frameNode?.removeChild(frameNode?.getChild(0))
144e41f4b71Sopenharmony_ci          console.log(TEST_TAG + " removeChild success ");
145e41f4b71Sopenharmony_ci        } catch (err) {
146e41f4b71Sopenharmony_ci          console.log(TEST_TAG + " removeChild fail : " + (err as BusinessError).code + " : " + (err as BusinessError).message);
147e41f4b71Sopenharmony_ci        }
148e41f4b71Sopenharmony_ci      }, 2000)
149e41f4b71Sopenharmony_ci      setTimeout(() => {
150e41f4b71Sopenharmony_ci        try {
151e41f4b71Sopenharmony_ci          frameNode?.clearChildren();
152e41f4b71Sopenharmony_ci          console.log(TEST_TAG + " clearChildren success ");
153e41f4b71Sopenharmony_ci        } catch (err) {
154e41f4b71Sopenharmony_ci          console.log(TEST_TAG + " clearChildren fail : " + (err as BusinessError).code + " : " + (err as BusinessError).message);
155e41f4b71Sopenharmony_ci        }
156e41f4b71Sopenharmony_ci      }, 4000)
157e41f4b71Sopenharmony_ci    }
158e41f4b71Sopenharmony_ci  }
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci  testInterfaceAboutSearch(frameNode: FrameNode | undefined | null): string {
161e41f4b71Sopenharmony_ci    let result: string = "";
162e41f4b71Sopenharmony_ci    if (frameNode) {
163e41f4b71Sopenharmony_ci      result = result + `current node is ${frameNode.getNodeType()} \n`;
164e41f4b71Sopenharmony_ci      result = result + `parent node is ${frameNode.getParent()?.getNodeType()} \n`;
165e41f4b71Sopenharmony_ci      result = result + `child count is ${frameNode.getChildrenCount()} \n`;
166e41f4b71Sopenharmony_ci      result = result + `first child node is ${frameNode.getFirstChild()?.getNodeType()} \n`;
167e41f4b71Sopenharmony_ci      result = result + `second child node is ${frameNode.getChild(1)?.getNodeType()} \n`;
168e41f4b71Sopenharmony_ci      result = result + `previousSibling node is ${frameNode.getPreviousSibling()?.getNodeType()} \n`;
169e41f4b71Sopenharmony_ci      result = result + `nextSibling node is ${frameNode.getNextSibling()?.getNodeType()} \n`;
170e41f4b71Sopenharmony_ci    }
171e41f4b71Sopenharmony_ci    return result;
172e41f4b71Sopenharmony_ci  }
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci  checkAppendChild(parent: FrameNode | undefined | null, child: FrameNode | undefined | null) {
175e41f4b71Sopenharmony_ci    try {
176e41f4b71Sopenharmony_ci      if (parent && child) {
177e41f4b71Sopenharmony_ci        parent.appendChild(child);
178e41f4b71Sopenharmony_ci        console.log(TEST_TAG + " appendChild success ");
179e41f4b71Sopenharmony_ci      }
180e41f4b71Sopenharmony_ci    } catch (err) {
181e41f4b71Sopenharmony_ci      console.log(TEST_TAG + " appendChild fail : " + (err as BusinessError).code + " : " + (err as BusinessError).message);
182e41f4b71Sopenharmony_ci    }
183e41f4b71Sopenharmony_ci  }
184e41f4b71Sopenharmony_ci}
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci@Entry
187e41f4b71Sopenharmony_ci@Component
188e41f4b71Sopenharmony_cistruct Index {
189e41f4b71Sopenharmony_ci  @State index: number = 0;
190e41f4b71Sopenharmony_ci  @State result: string = ""
191e41f4b71Sopenharmony_ci  private myNodeController: MyNodeController = new MyNodeController();
192e41f4b71Sopenharmony_ci
193e41f4b71Sopenharmony_ci  build() {
194e41f4b71Sopenharmony_ci    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
195e41f4b71Sopenharmony_ci      List({ space: 20, initialIndex: 0 }) {
196e41f4b71Sopenharmony_ci        ListItem() {
197e41f4b71Sopenharmony_ci          Column({ space: 5 }) {
198e41f4b71Sopenharmony_ci            Text("Verify the add, delete, and modify features of the FrameNode")
199e41f4b71Sopenharmony_ci            Button("Operate Custom FrameNode")
200e41f4b71Sopenharmony_ci              .fontSize(16)
201e41f4b71Sopenharmony_ci              .width(400)
202e41f4b71Sopenharmony_ci              .onClick(() => {
203e41f4b71Sopenharmony_ci                // Add, delete, and modify FrameNode child nodes, which is properly implemented.
204e41f4b71Sopenharmony_ci                this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.frameNode);
205e41f4b71Sopenharmony_ci              })
206e41f4b71Sopenharmony_ci            Button("Operate Proxy Node in BuilderNode")
207e41f4b71Sopenharmony_ci              .fontSize(16)
208e41f4b71Sopenharmony_ci              .width(400)
209e41f4b71Sopenharmony_ci              .onClick(() => {
210e41f4b71Sopenharmony_ci                // Add, delete, and modify the BuilderNode proxy nodes, which results in an exception.
211e41f4b71Sopenharmony_ci                this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.buttonNode?.getFrameNode());
212e41f4b71Sopenharmony_ci              })
213e41f4b71Sopenharmony_ci            Button("Operate Proxy Node in Built-in Component")
214e41f4b71Sopenharmony_ci              .fontSize(16)
215e41f4b71Sopenharmony_ci              .width(400)
216e41f4b71Sopenharmony_ci              .onClick(() => {
217e41f4b71Sopenharmony_ci                // Add, delete, and modify the proxy nodes, which results in an exception.
218e41f4b71Sopenharmony_ci                this.myNodeController.operationFrameNodeWithFrameNode(this.myNodeController?.rootNode?.getParent());
219e41f4b71Sopenharmony_ci              })
220e41f4b71Sopenharmony_ci          }
221e41f4b71Sopenharmony_ci        }
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci        ListItem() {
224e41f4b71Sopenharmony_ci          Column({ space: 5 }) {
225e41f4b71Sopenharmony_ci            Text("Verify the feature to add subnodes to FrameNode")
226e41f4b71Sopenharmony_ci            Button("Add BuilderNode Proxy Node")
227e41f4b71Sopenharmony_ci              .fontSize(16)
228e41f4b71Sopenharmony_ci              .width(400)
229e41f4b71Sopenharmony_ci              .onClick(() => {
230e41f4b71Sopenharmony_ci                let buttonNode = new BuilderNode<[Params]>(this.getUIContext());
231e41f4b71Sopenharmony_ci                buttonNode.build(wrapBuilder<[Params]>(buttonBuilder), { text: "BUTTON" })
232e41f4b71Sopenharmony_ci                this.myNodeController.checkAppendChild(this.myNodeController?.frameNode, buttonNode?.getFrameNode());
233e41f4b71Sopenharmony_ci              })
234e41f4b71Sopenharmony_ci            Button("Add Built-in Component Proxy Node")
235e41f4b71Sopenharmony_ci              .fontSize(16)
236e41f4b71Sopenharmony_ci              .width(400)
237e41f4b71Sopenharmony_ci              .onClick(() => {
238e41f4b71Sopenharmony_ci                this.myNodeController.checkAppendChild(this.myNodeController?.frameNode, this.myNodeController?.rootNode?.getParent());
239e41f4b71Sopenharmony_ci              })
240e41f4b71Sopenharmony_ci            Button("Add Custom Node with Existing Parent Node")
241e41f4b71Sopenharmony_ci              .fontSize(16)
242e41f4b71Sopenharmony_ci              .width(400)
243e41f4b71Sopenharmony_ci              .onClick(() => {
244e41f4b71Sopenharmony_ci                this.myNodeController.checkAppendChild(this.myNodeController?.frameNode, this.myNodeController?.rootNode);
245e41f4b71Sopenharmony_ci              })
246e41f4b71Sopenharmony_ci          }
247e41f4b71Sopenharmony_ci        }
248e41f4b71Sopenharmony_ci
249e41f4b71Sopenharmony_ci        ListItem() {
250e41f4b71Sopenharmony_ci          Column({ space: 5 }) {
251e41f4b71Sopenharmony_ci            Text("Verify the query feature of the FrameNode")
252e41f4b71Sopenharmony_ci            Button("Operate Custom FrameNode")
253e41f4b71Sopenharmony_ci              .fontSize(16)
254e41f4b71Sopenharmony_ci              .width(400)
255e41f4b71Sopenharmony_ci              .onClick(() => {
256e41f4b71Sopenharmony_ci                // Query the FrameNode. The current node is a child of the NodeContainer.
257e41f4b71Sopenharmony_ci                this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.rootNode);
258e41f4b71Sopenharmony_ci                setTimeout(() => {
259e41f4b71Sopenharmony_ci                  // Query the FrameNode. The current node is the first child node under rootNode.
260e41f4b71Sopenharmony_ci                  this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.frameNode);
261e41f4b71Sopenharmony_ci                }, 2000)
262e41f4b71Sopenharmony_ci              })
263e41f4b71Sopenharmony_ci            Button("Operate Proxy Node in BuilderNode")
264e41f4b71Sopenharmony_ci              .fontSize(16)
265e41f4b71Sopenharmony_ci              .width(400)
266e41f4b71Sopenharmony_ci              .onClick(() => {
267e41f4b71Sopenharmony_ci                // Query the BuilderNode proxy nodes. The current node is the Column node within BuilderNode.
268e41f4b71Sopenharmony_ci                this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.buttonNode?.getFrameNode());
269e41f4b71Sopenharmony_ci              })
270e41f4b71Sopenharmony_ci            Button("Operate Proxy Node in Built-in Component")
271e41f4b71Sopenharmony_ci              .fontSize(16)
272e41f4b71Sopenharmony_ci              .width(400)
273e41f4b71Sopenharmony_ci              .onClick(() => {
274e41f4b71Sopenharmony_ci                // Query the proxy node. The current node is the NodeContainer.
275e41f4b71Sopenharmony_ci                this.result = this.myNodeController.testInterfaceAboutSearch(this.myNodeController?.rootNode?.getParent());
276e41f4b71Sopenharmony_ci              })
277e41f4b71Sopenharmony_ci          }
278e41f4b71Sopenharmony_ci        }
279e41f4b71Sopenharmony_ci      }.height("50%")
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci      Text(`Result: \n${this.result}`)
282e41f4b71Sopenharmony_ci        .fontSize(16)
283e41f4b71Sopenharmony_ci        .width(400)
284e41f4b71Sopenharmony_ci        .height(200)
285e41f4b71Sopenharmony_ci        .padding(30)
286e41f4b71Sopenharmony_ci        .borderWidth(1)
287e41f4b71Sopenharmony_ci      Column() {
288e41f4b71Sopenharmony_ci        Text("This is a NodeContainer.")
289e41f4b71Sopenharmony_ci          .textAlign(TextAlign.Center)
290e41f4b71Sopenharmony_ci          .borderRadius(10)
291e41f4b71Sopenharmony_ci          .backgroundColor(0xFFFFFF)
292e41f4b71Sopenharmony_ci          .width('100%')
293e41f4b71Sopenharmony_ci          .fontSize(16)
294e41f4b71Sopenharmony_ci        NodeContainer(this.myNodeController)
295e41f4b71Sopenharmony_ci          .borderWidth(1)
296e41f4b71Sopenharmony_ci          .width(400)
297e41f4b71Sopenharmony_ci          .height(150)
298e41f4b71Sopenharmony_ci      }
299e41f4b71Sopenharmony_ci    }
300e41f4b71Sopenharmony_ci    .padding({ left: 35, right: 35, top: 35, bottom: 35 })
301e41f4b71Sopenharmony_ci    .width("100%")
302e41f4b71Sopenharmony_ci    .height("100%")
303e41f4b71Sopenharmony_ci  }
304e41f4b71Sopenharmony_ci}
305e41f4b71Sopenharmony_ci```
306e41f4b71Sopenharmony_ci
307e41f4b71Sopenharmony_ci## Setting Universal Attributes and Event Callbacks
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ciUse the [commonAttribute](../reference/apis-arkui/js-apis-arkui-frameNode.md#commonattribute12) and [commonEvent](../reference/apis-arkui/js-apis-arkui-frameNode.md#commonevent12) objects to set the [universal attributes](../reference/apis-arkui/arkui-ts/ts-universal-attributes-size.md) and [event callbacks](../reference/apis-arkui/arkui-ts/ts-uicommonevent.md), respectively.
310e41f4b71Sopenharmony_ci
311e41f4b71Sopenharmony_ci> **NOTE**
312e41f4b71Sopenharmony_ci> 
313e41f4b71Sopenharmony_ci> - Proxy node attributes are immutable. Therefore, **commonAttribute** is ineffective on proxy nodes.
314e41f4b71Sopenharmony_ci> 
315e41f4b71Sopenharmony_ci> - The custom basic events that you define run in parallel with the events predefined in the built-in components, without overriding them. When two event callbacks are set, the built-in component event callback is prioritized.
316e41f4b71Sopenharmony_ci
317e41f4b71Sopenharmony_ci```ts
318e41f4b71Sopenharmony_ciimport { BuilderNode, FrameNode, NodeController, UIContext } from '@kit.ArkUI'
319e41f4b71Sopenharmony_ci
320e41f4b71Sopenharmony_ciclass Params {
321e41f4b71Sopenharmony_ci  text: string = "this is a text"
322e41f4b71Sopenharmony_ci}
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci@Builder
325e41f4b71Sopenharmony_cifunction buttonBuilder(params: Params) {
326e41f4b71Sopenharmony_ci  Button(params.text)
327e41f4b71Sopenharmony_ci    .fontSize(12)
328e41f4b71Sopenharmony_ci    .borderRadius(8)
329e41f4b71Sopenharmony_ci    .borderWidth(2)
330e41f4b71Sopenharmony_ci    .backgroundColor(Color.Orange)
331e41f4b71Sopenharmony_ci    .onClick((event: ClickEvent) => {
332e41f4b71Sopenharmony_ci      console.log(`Button ${JSON.stringify(event)}`);
333e41f4b71Sopenharmony_ci    })
334e41f4b71Sopenharmony_ci}
335e41f4b71Sopenharmony_ci
336e41f4b71Sopenharmony_ciclass MyNodeController extends NodeController {
337e41f4b71Sopenharmony_ci  public buttonNode: BuilderNode<[Params]> | null = null;
338e41f4b71Sopenharmony_ci  public frameNode: FrameNode | null = null;
339e41f4b71Sopenharmony_ci  public rootNode: FrameNode | null = null;
340e41f4b71Sopenharmony_ci  private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(buttonBuilder);
341e41f4b71Sopenharmony_ci
342e41f4b71Sopenharmony_ci  makeNode(uiContext: UIContext): FrameNode | null {
343e41f4b71Sopenharmony_ci    if (this.rootNode == null) {
344e41f4b71Sopenharmony_ci      this.rootNode = new FrameNode(uiContext);
345e41f4b71Sopenharmony_ci      // Modify the attributes of rootNode, which is a custom FrameNode, and the changes take effect.
346e41f4b71Sopenharmony_ci      this.rootNode.commonAttribute
347e41f4b71Sopenharmony_ci        .width("100%")
348e41f4b71Sopenharmony_ci        .height(100)
349e41f4b71Sopenharmony_ci        .borderWidth(1)
350e41f4b71Sopenharmony_ci        .backgroundColor(Color.Gray)
351e41f4b71Sopenharmony_ci    }
352e41f4b71Sopenharmony_ci
353e41f4b71Sopenharmony_ci    if (this.frameNode == null) {
354e41f4b71Sopenharmony_ci      this.frameNode = new FrameNode(uiContext);
355e41f4b71Sopenharmony_ci      // Modify the attributes of frameNode, which is a custom FrameNode, and the changes take effect.
356e41f4b71Sopenharmony_ci      this.frameNode.commonAttribute
357e41f4b71Sopenharmony_ci        .width("50%")
358e41f4b71Sopenharmony_ci        .height(50)
359e41f4b71Sopenharmony_ci        .borderWidth(1)
360e41f4b71Sopenharmony_ci        .backgroundColor(Color.Pink);
361e41f4b71Sopenharmony_ci      this.rootNode.appendChild(this.frameNode);
362e41f4b71Sopenharmony_ci    }
363e41f4b71Sopenharmony_ci    if (this.buttonNode == null) {
364e41f4b71Sopenharmony_ci      this.buttonNode = new BuilderNode<[Params]>(uiContext);
365e41f4b71Sopenharmony_ci      this.buttonNode.build(this.wrapBuilder, { text: "This is a Button" })
366e41f4b71Sopenharmony_ci      // Modify the attributes of the FrameNode obtained from BuilderNode, which is not a custom FrameNode, and the changes do not take effect.
367e41f4b71Sopenharmony_ci      this.buttonNode?.getFrameNode()?.commonAttribute.position({ x: 100, y: 100 })
368e41f4b71Sopenharmony_ci      this.rootNode.appendChild(this.buttonNode.getFrameNode())
369e41f4b71Sopenharmony_ci    }
370e41f4b71Sopenharmony_ci    return this.rootNode;
371e41f4b71Sopenharmony_ci  }
372e41f4b71Sopenharmony_ci
373e41f4b71Sopenharmony_ci  modifyNode(frameNode: FrameNode | null | undefined, sizeValue: SizeOptions, positionValue: Position) {
374e41f4b71Sopenharmony_ci    if (frameNode) {
375e41f4b71Sopenharmony_ci      frameNode.commonAttribute.size(sizeValue).position(positionValue);
376e41f4b71Sopenharmony_ci    }
377e41f4b71Sopenharmony_ci  }
378e41f4b71Sopenharmony_ci
379e41f4b71Sopenharmony_ci  addClickEvent(frameNode: FrameNode | null | undefined) {
380e41f4b71Sopenharmony_ci    if (frameNode) {
381e41f4b71Sopenharmony_ci      frameNode.commonEvent.setOnClick((event: ClickEvent) => {
382e41f4b71Sopenharmony_ci        console.log(`FrameNode ${JSON.stringify(event)}`);
383e41f4b71Sopenharmony_ci      })
384e41f4b71Sopenharmony_ci    }
385e41f4b71Sopenharmony_ci  }
386e41f4b71Sopenharmony_ci}
387e41f4b71Sopenharmony_ci
388e41f4b71Sopenharmony_ci@Entry
389e41f4b71Sopenharmony_ci@Component
390e41f4b71Sopenharmony_cistruct Index {
391e41f4b71Sopenharmony_ci  private myNodeController: MyNodeController = new MyNodeController();
392e41f4b71Sopenharmony_ci
393e41f4b71Sopenharmony_ci  build() {
394e41f4b71Sopenharmony_ci    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
395e41f4b71Sopenharmony_ci      Column({ space: 10 }) {
396e41f4b71Sopenharmony_ci        Text("Modify the universal node attributes: width and height.")
397e41f4b71Sopenharmony_ci        Button("modify ArkTS-FrameNode")
398e41f4b71Sopenharmony_ci          .onClick(() => {
399e41f4b71Sopenharmony_ci            // The object obtained is the FrameNode created on the current page, which can be modified. That is, the size and position of the node can be changed.
400e41f4b71Sopenharmony_ci            console.log("Check whether the node can be modified " + this.myNodeController?.frameNode
401e41f4b71Sopenharmony_ci            ?.isModifiable());
402e41f4b71Sopenharmony_ci            this.myNodeController.modifyNode(this.myNodeController?.frameNode, { width: 150, height: 100 }, {
403e41f4b71Sopenharmony_ci              x: 100,
404e41f4b71Sopenharmony_ci              y: 0
405e41f4b71Sopenharmony_ci            })
406e41f4b71Sopenharmony_ci          })
407e41f4b71Sopenharmony_ci        Button("modify FrameNode get by BuilderNode")
408e41f4b71Sopenharmony_ci          .onClick(() => {
409e41f4b71Sopenharmony_ci            // The object obtained is the root node of the BuilderNode on the current page, which cannot be modified. That is, the size and position of the node remain unchanged.
410e41f4b71Sopenharmony_ci            console.log("Check the weather the node can be modified " + this.myNodeController?.buttonNode?.getFrameNode()
411e41f4b71Sopenharmony_ci            ?.isModifiable());
412e41f4b71Sopenharmony_ci            this.myNodeController.modifyNode(this.myNodeController?.buttonNode?.getFrameNode(), {
413e41f4b71Sopenharmony_ci              width: 100,
414e41f4b71Sopenharmony_ci              height: 100
415e41f4b71Sopenharmony_ci            }, { x: 50, y: 50 })
416e41f4b71Sopenharmony_ci          })
417e41f4b71Sopenharmony_ci        Button("modify proxyFrameNode get by search")
418e41f4b71Sopenharmony_ci          .onClick(() => {
419e41f4b71Sopenharmony_ci            // The rootNode object calling getParent() obtains the NodeContainer node on the current page, which cannot be modified. That is, the size and position of the node remain unchanged.
420e41f4b71Sopenharmony_ci            console.log("Check the weather the node can be modified " + this.myNodeController?.rootNode?.getParent()
421e41f4b71Sopenharmony_ci            ?.isModifiable());
422e41f4b71Sopenharmony_ci            this.myNodeController.modifyNode(this.myNodeController?.rootNode?.getParent(), {
423e41f4b71Sopenharmony_ci              width: 500,
424e41f4b71Sopenharmony_ci              height: 500
425e41f4b71Sopenharmony_ci            }, {
426e41f4b71Sopenharmony_ci              x: 0,
427e41f4b71Sopenharmony_ci              y: 0
428e41f4b71Sopenharmony_ci            })
429e41f4b71Sopenharmony_ci          })
430e41f4b71Sopenharmony_ci      }.padding({ left: 35, right: 35, top: 35, bottom: 35 })
431e41f4b71Sopenharmony_ci
432e41f4b71Sopenharmony_ci      Column({ space: 10 }) {
433e41f4b71Sopenharmony_ci        Text("Modify the node click event.")
434e41f4b71Sopenharmony_ci        Button("add click event to ArkTS-FrameNode")
435e41f4b71Sopenharmony_ci          .onClick(() => {
436e41f4b71Sopenharmony_ci            // The object obtained is the FrameNode created on the current page, to which click events can be added.
437e41f4b71Sopenharmony_ci            // The added click event participates in event competition, meaning the click event will be consumed by this node and will no longer bubble up to the parent component.
438e41f4b71Sopenharmony_ci            console.log("Check the weather the node can be modified " + this.myNodeController?.rootNode?.getParent()
439e41f4b71Sopenharmony_ci            ?.isModifiable());
440e41f4b71Sopenharmony_ci            this.myNodeController.addClickEvent(this.myNodeController?.frameNode)
441e41f4b71Sopenharmony_ci          })
442e41f4b71Sopenharmony_ci        Button("add click event to FrameNode get by BuilderNode")
443e41f4b71Sopenharmony_ci          .onClick(() => {
444e41f4b71Sopenharmony_ci            // The object obtained is the root node of the BuilderNode on the current page, to which click events can be added.
445e41f4b71Sopenharmony_ci            // When the button is clicked, the click event callback set through the built-in component API is called first, followed by the click listener added through commonEvent.
446e41f4b71Sopenharmony_ci            console.log("Check the weather the node can be modified " + this.myNodeController?.buttonNode?.getFrameNode()
447e41f4b71Sopenharmony_ci            ?.isModifiable());
448e41f4b71Sopenharmony_ci            this.myNodeController.addClickEvent(this.myNodeController?.buttonNode?.getFrameNode())
449e41f4b71Sopenharmony_ci          })
450e41f4b71Sopenharmony_ci        Button("add click event to proxyFrameNode get by search")
451e41f4b71Sopenharmony_ci          .onClick(() => {
452e41f4b71Sopenharmony_ci            // The rootNode object calling getParent() obtains the NodeContainer node on the current page, to which click events can be added.
453e41f4b71Sopenharmony_ci            console.log("Check the weather the node can be modified " + this.myNodeController?.rootNode?.getParent()
454e41f4b71Sopenharmony_ci            ?.isModifiable());
455e41f4b71Sopenharmony_ci            this.myNodeController.addClickEvent(this.myNodeController?.rootNode?.getParent());
456e41f4b71Sopenharmony_ci          })
457e41f4b71Sopenharmony_ci      }.padding({ left: 35, right: 35, top: 35, bottom: 35 })
458e41f4b71Sopenharmony_ci
459e41f4b71Sopenharmony_ci      NodeContainer(this.myNodeController)
460e41f4b71Sopenharmony_ci        .borderWidth(1)
461e41f4b71Sopenharmony_ci        .width("100%")
462e41f4b71Sopenharmony_ci        .height(100)
463e41f4b71Sopenharmony_ci        .onClick((event: ClickEvent) => {
464e41f4b71Sopenharmony_ci          console.log(`NodeContainer ${JSON.stringify(event)}`);
465e41f4b71Sopenharmony_ci        })
466e41f4b71Sopenharmony_ci    }
467e41f4b71Sopenharmony_ci    .padding({ left: 35, right: 35, top: 35, bottom: 35 })
468e41f4b71Sopenharmony_ci    .width("100%")
469e41f4b71Sopenharmony_ci    .height("100%")
470e41f4b71Sopenharmony_ci  }
471e41f4b71Sopenharmony_ci}
472e41f4b71Sopenharmony_ci```
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci## Implementing Custom Measurement, Layout, and Drawing
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ciBy overriding the [onDraw](../reference/apis-arkui/js-apis-arkui-frameNode.md#ondraw12) API, you can customize the drawing content of the FrameNode. Use the [invalidate](../reference/apis-arkui/js-apis-arkui-frameNode.md#invalidate12) API to manually trigger a redraw of the node.
477e41f4b71Sopenharmony_ci
478e41f4b71Sopenharmony_ciBy overriding the [onMeasure](../reference/apis-arkui/js-apis-arkui-frameNode.md#onmeasure12) API, you can customize how the FrameNode measures its size. Use [measure](../reference/apis-arkui/js-apis-arkui-frameNode.md#measure12) to proactively pass layout constraints to initiate a remeasurement.
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ciBy overriding the [onLayout](../reference/apis-arkui/js-apis-arkui-frameNode.md#onlayout12) API, you can customize the layout of the FrameNode. Use [layout](../reference/apis-arkui/js-apis-arkui-frameNode.md#layout12) to proactively pass position information and initiate a re-layout.
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ciUse [setNeedsLayout](../reference/apis-arkui/js-apis-arkui-frameNode.md#setneedslayout12) to mark the current node and trigger a re-layout in the next frame.
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci> **NOTE**
485e41f4b71Sopenharmony_ci> 
486e41f4b71Sopenharmony_ci> - After a node is disposed and unbound, the FrameNode no longer represents an entity node. In this case, the **invalidate** call cannot update the previously bound node.
487e41f4b71Sopenharmony_ci> 
488e41f4b71Sopenharmony_ci> - Custom drawings made through the **onDraw** API cannot exceed the component's size.
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ci```ts
491e41f4b71Sopenharmony_ciimport { DrawContext, FrameNode, NodeController, Position, Size, UIContext, LayoutConstraint } from '@kit.ArkUI';
492e41f4b71Sopenharmony_ciimport { drawing } from '@kit.ArkGraphics2D';
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_cifunction GetChildLayoutConstraint(constraint: LayoutConstraint, child: FrameNode): LayoutConstraint {
495e41f4b71Sopenharmony_ci  const size = child.getUserConfigSize();
496e41f4b71Sopenharmony_ci  const width = Math.max(
497e41f4b71Sopenharmony_ci    Math.min(constraint.maxSize.width, size.width.value),
498e41f4b71Sopenharmony_ci    constraint.minSize.width
499e41f4b71Sopenharmony_ci  );
500e41f4b71Sopenharmony_ci  const height = Math.max(
501e41f4b71Sopenharmony_ci    Math.min(constraint.maxSize.height, size.height.value),
502e41f4b71Sopenharmony_ci    constraint.minSize.height
503e41f4b71Sopenharmony_ci  );
504e41f4b71Sopenharmony_ci  const finalSize: Size = { width, height };
505e41f4b71Sopenharmony_ci  const res: LayoutConstraint = {
506e41f4b71Sopenharmony_ci    maxSize: finalSize,
507e41f4b71Sopenharmony_ci    minSize: finalSize,
508e41f4b71Sopenharmony_ci    percentReference: finalSize
509e41f4b71Sopenharmony_ci  };
510e41f4b71Sopenharmony_ci
511e41f4b71Sopenharmony_ci  return res;
512e41f4b71Sopenharmony_ci}
513e41f4b71Sopenharmony_ci
514e41f4b71Sopenharmony_ciclass MyFrameNode extends FrameNode {
515e41f4b71Sopenharmony_ci  public width: number = 100;
516e41f4b71Sopenharmony_ci  public offsetY: number = 0;
517e41f4b71Sopenharmony_ci  private space: number = 1;
518e41f4b71Sopenharmony_ci
519e41f4b71Sopenharmony_ci  onMeasure(constraint: LayoutConstraint): void {
520e41f4b71Sopenharmony_ci    let sizeRes: Size = { width: vp2px(100), height: vp2px(100) };
521e41f4b71Sopenharmony_ci    for (let i = 0;i < this.getChildrenCount(); i++) {
522e41f4b71Sopenharmony_ci      let child = this.getChild(i);
523e41f4b71Sopenharmony_ci      if (child) {
524e41f4b71Sopenharmony_ci        let childConstraint = GetChildLayoutConstraint(constraint, child);
525e41f4b71Sopenharmony_ci        child.measure(childConstraint);
526e41f4b71Sopenharmony_ci        let size = child.getMeasuredSize();
527e41f4b71Sopenharmony_ci        sizeRes.height += size.height + this.space;
528e41f4b71Sopenharmony_ci        sizeRes.width = Math.max(sizeRes.width, size.width);
529e41f4b71Sopenharmony_ci      }
530e41f4b71Sopenharmony_ci    }
531e41f4b71Sopenharmony_ci    this.setMeasuredSize(sizeRes);
532e41f4b71Sopenharmony_ci  }
533e41f4b71Sopenharmony_ci
534e41f4b71Sopenharmony_ci  onLayout(position: Position): void {
535e41f4b71Sopenharmony_ci    let y = 0;
536e41f4b71Sopenharmony_ci    for (let i = 0;i < this.getChildrenCount(); i++) {
537e41f4b71Sopenharmony_ci      let child = this.getChild(i);
538e41f4b71Sopenharmony_ci      if (child) {
539e41f4b71Sopenharmony_ci        child.layout({
540e41f4b71Sopenharmony_ci          x: vp2px(100),
541e41f4b71Sopenharmony_ci          y: vp2px(this.offsetY)
542e41f4b71Sopenharmony_ci        });
543e41f4b71Sopenharmony_ci        y += child.getMeasuredSize().height + this.space;
544e41f4b71Sopenharmony_ci      }
545e41f4b71Sopenharmony_ci    }
546e41f4b71Sopenharmony_ci    this.setLayoutPosition(position);
547e41f4b71Sopenharmony_ci  }
548e41f4b71Sopenharmony_ci
549e41f4b71Sopenharmony_ci  onDraw(context: DrawContext) {
550e41f4b71Sopenharmony_ci    const canvas = context.canvas;
551e41f4b71Sopenharmony_ci    const pen = new drawing.Pen();
552e41f4b71Sopenharmony_ci    pen.setStrokeWidth(15);
553e41f4b71Sopenharmony_ci    pen.setColor({ alpha: 255, red: 255, green: 0, blue: 0 });
554e41f4b71Sopenharmony_ci    canvas.attachPen(pen);
555e41f4b71Sopenharmony_ci    canvas.drawRect({  
556e41f4b71Sopenharmony_ci      left: 50, 
557e41f4b71Sopenharmony_ci      right: this.width + 50, 
558e41f4b71Sopenharmony_ci      top: 50, 
559e41f4b71Sopenharmony_ci      bottom: this.width + 50,
560e41f4b71Sopenharmony_ci    });
561e41f4b71Sopenharmony_ci    canvas.detachPen();
562e41f4b71Sopenharmony_ci  }
563e41f4b71Sopenharmony_ci
564e41f4b71Sopenharmony_ci  addWidth() {
565e41f4b71Sopenharmony_ci    this.width = (this.width + 10) % 50 + 100;
566e41f4b71Sopenharmony_ci  }
567e41f4b71Sopenharmony_ci}
568e41f4b71Sopenharmony_ci
569e41f4b71Sopenharmony_ciclass MyNodeController extends NodeController {
570e41f4b71Sopenharmony_ci  public rootNode: MyFrameNode | null = null;
571e41f4b71Sopenharmony_ci
572e41f4b71Sopenharmony_ci  makeNode(context: UIContext): FrameNode | null {
573e41f4b71Sopenharmony_ci    this.rootNode = new MyFrameNode(context);
574e41f4b71Sopenharmony_ci    this.rootNode?.commonAttribute?.size({ width: 100, height: 100 }).backgroundColor(Color.Green);
575e41f4b71Sopenharmony_ci    let frameNode: FrameNode = new FrameNode(context);
576e41f4b71Sopenharmony_ci    this.rootNode.appendChild(frameNode);
577e41f4b71Sopenharmony_ci    frameNode.commonAttribute.width(10).height(10).backgroundColor(Color.Pink);
578e41f4b71Sopenharmony_ci    return this.rootNode;
579e41f4b71Sopenharmony_ci  }
580e41f4b71Sopenharmony_ci}
581e41f4b71Sopenharmony_ci
582e41f4b71Sopenharmony_ci@Entry
583e41f4b71Sopenharmony_ci@Component
584e41f4b71Sopenharmony_cistruct Index {
585e41f4b71Sopenharmony_ci  private nodeController: MyNodeController = new MyNodeController();
586e41f4b71Sopenharmony_ci
587e41f4b71Sopenharmony_ci  build() {
588e41f4b71Sopenharmony_ci    Row() {
589e41f4b71Sopenharmony_ci      Column() {
590e41f4b71Sopenharmony_ci        NodeContainer(this.nodeController)
591e41f4b71Sopenharmony_ci          .width('100%')
592e41f4b71Sopenharmony_ci          .height(200)
593e41f4b71Sopenharmony_ci          .backgroundColor('#FFF0F0F0')
594e41f4b71Sopenharmony_ci        Button('Invalidate')
595e41f4b71Sopenharmony_ci          .margin(10)
596e41f4b71Sopenharmony_ci          .onClick(() => {
597e41f4b71Sopenharmony_ci            this.nodeController?.rootNode?.addWidth();
598e41f4b71Sopenharmony_ci            this.nodeController?.rootNode?.invalidate();
599e41f4b71Sopenharmony_ci          })
600e41f4b71Sopenharmony_ci        Button('UpdateLayout')
601e41f4b71Sopenharmony_ci          .onClick(() => {
602e41f4b71Sopenharmony_ci            let node = this.nodeController.rootNode;
603e41f4b71Sopenharmony_ci            node!.offsetY = (node!.offsetY + 10) % 110;
604e41f4b71Sopenharmony_ci            this.nodeController?.rootNode?.setNeedsLayout();
605e41f4b71Sopenharmony_ci          })
606e41f4b71Sopenharmony_ci      }
607e41f4b71Sopenharmony_ci      .width('100%')
608e41f4b71Sopenharmony_ci      .height('100%')
609e41f4b71Sopenharmony_ci    }
610e41f4b71Sopenharmony_ci    .height('100%')
611e41f4b71Sopenharmony_ci  }
612e41f4b71Sopenharmony_ci}
613e41f4b71Sopenharmony_ci```
614e41f4b71Sopenharmony_ci
615e41f4b71Sopenharmony_ci## Searching for Nodes and Obtaining Basic Information
616e41f4b71Sopenharmony_ci
617e41f4b71Sopenharmony_ci**FrameNode** provides APIs for obtaining basic information about an entity node. For details about the returned information, see the FrameNode API documentation.
618e41f4b71Sopenharmony_ci
619e41f4b71Sopenharmony_ciTo obtain a FrameNode, use any of the following methods:
620e41f4b71Sopenharmony_ci
621e41f4b71Sopenharmony_ci1. Use [getFrameNodeById](../reference/apis-arkui/js-apis-arkui-UIContext.md#getframenodebyid12).
622e41f4b71Sopenharmony_ci
623e41f4b71Sopenharmony_ci2. Use [getFrameNodeByUniqueId](../reference/apis-arkui/js-apis-arkui-UIContext.md#getframenodebyuniqueid12).
624e41f4b71Sopenharmony_ci
625e41f4b71Sopenharmony_ci3. Use an [observer](../reference/apis-arkui/js-apis-arkui-observer.md).
626e41f4b71Sopenharmony_ci
627e41f4b71Sopenharmony_ci> **NOTE**
628e41f4b71Sopenharmony_ci>
629e41f4b71Sopenharmony_ci> Currently, the following information can be obtained:
630e41f4b71Sopenharmony_ci>
631e41f4b71Sopenharmony_ci> - Node size: **getMeasuredSize**, **getUserConfigSize**
632e41f4b71Sopenharmony_ci> 
633e41f4b71Sopenharmony_ci> - Layout information: **getPositionToWindow**, **getPositionToParent**, **getLayoutPosition**, **getUserConfigBorderWidth**, **getUserConfigPadding**, **getUserConfigMargin**
634e41f4b71Sopenharmony_ci> 
635e41f4b71Sopenharmony_ci> - Node information: **getId**, **getUniqueId**, **getNodeType**, **getOpacity**, **isVisible**, **isClipToFrame**, **isAttached**, **getInspectorInfo**, **getCustomProperty**
636