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