1# Custom Component Layout 2 3The custom layout of a custom component is used to lay out its child components through data calculation. 4 5> **NOTE** 6> 7> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version. 8 9## onPlaceChildren<sup>10+</sup> 10 11onPlaceChildren?(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions):void 12 13Invoked when the custom component lays out its child components. Through this callback the component receives its child component size constraints from the ArkUI framework. State variables should not be changed in this callback. 14 15**Atomic service API**: This API can be used in atomic services since API version 11. 16 17**System capability**: SystemCapability.ArkUI.ArkUI.Full 18 19**Parameters** 20 21| Name | Type |Mandatory| Description | 22|----------------|------------------------------------------------------------|---|------------------| 23| selfLayoutInfo | [GeometryInfo](#geometryinfo10) |Yes|Layout information of the custom component itself after measurement. | 24| children | Array<[Layoutable](#layoutable10)> |Yes|Layout information of the child components after measurement. | 25| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) |Yes|Size constraint of the parent component.| 26 27**Example** 28 29See the [example for customizing a layout](#onmeasuresize10). 30 31## onMeasureSize<sup>10+</sup> 32 33onMeasureSize?(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions): SizeResult 34 35Invoked when the custom component needs to determine its size. Through this callback the component receives its child component layout information and size constraint from the ArkUI framework. State variables should not be changed in this callback. 36 37**Atomic service API**: This API can be used in atomic services since API version 11. 38 39**System capability**: SystemCapability.ArkUI.ArkUI.Full 40 41**Parameters** 42 43| Name | Type | Mandatory|Description | 44| -------------- | ---------------------------------------------------------- | ---|------------------------------------------------------------ | 45| selfLayoutInfo | [GeometryInfo](#geometryinfo10) | Yes|Layout information of the custom component itself after measurement.<br>**NOTE**<br>During the first layout, the component will use its own set attributes as the basis for layout. | 46| children | Array<[Measurable](#measurable10)> | Yes|Layout information of the child components after measurement.<br>**NOTE**<br>When a child component does not have its layout information set, it retains the previous layout settings or, if no previous layout settings are available, stays at the default size of 0.| 47| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Yes|Size constraint of the parent component. | 48 49**Return value** 50 51| Type | Description | 52| --------------------------- | -------------- | 53| [SizeResult](#sizeresult10) | Component size information.| 54 55**Example 1** 56This example demonstrates how to customize a layout. 57```ts 58// xxx.ets 59@Entry 60@Component 61struct Index { 62 build() { 63 Column() { 64 CustomLayout({ builder: ColumnChildren }) 65 } 66 } 67} 68 69@Builder 70function ColumnChildren() { 71 ForEach([1, 2, 3], (index: number) => {// LazyForEach is not supported. 72 Text('S' + index) 73 .fontSize(30) 74 .width(100) 75 .height(100) 76 .borderWidth(2) 77 .offset({ x: 10, y: 20 }) 78 }) 79} 80 81@Component 82struct CustomLayout { 83 @Builder 84 doNothingBuilder() { 85 }; 86 87 @BuilderParam builder: () => void = this.doNothingBuilder; 88 @State startSize: number = 100; 89 result: SizeResult = { 90 width: 0, 91 height: 0 92 }; 93 94 onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) { 95 let startPos = 300; 96 children.forEach((child) => { 97 let pos = startPos - child.measureResult.height; 98 child.layout({ x: pos, y: pos }) 99 }) 100 } 101 102 onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) { 103 let size = 100; 104 children.forEach((child) => { 105 let result: MeasureResult = child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }) 106 size += result.width / 2 107 ; 108 }) 109 this.result.width = 100; 110 this.result.height = 400; 111 return this.result; 112 } 113 114 build() { 115 this.builder() 116 } 117} 118``` 119 120 121 122**Example 2** 123This example shows how to determine whether a component participates in layout calculation based on its position. 124```ts 125// xxx.ets 126@Entry 127@Component 128struct Index { 129 build() { 130 Column() { 131 CustomLayout({ builder: ColumnChildren }) 132 } 133 .justifyContent(FlexAlign.Center) 134 .width("100%") 135 .height("100%") 136 } 137} 138 139@Builder 140function ColumnChildren() { 141 ForEach([1, 2, 3], (item: number, index: number) => { // LazyForEach is not supported. 142 Text('S' + item) 143 .fontSize(20) 144 .width(60 + 10 * index) 145 .height(100) 146 .borderWidth(2) 147 .margin({ left:10 }) 148 .padding(10) 149 }) 150} 151 152@Component 153struct CustomLayout { 154 // Lay out only one row, and hide child components that are too large for the available space. 155 @Builder 156 doNothingBuilder() { 157 }; 158 159 @BuilderParam builder: () => void = this.doNothingBuilder; 160 result: SizeResult = { 161 width: 0, 162 height: 0 163 }; 164 overFlowIndex: number = -1; 165 166 onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) { 167 let currentX = 0; 168 let infinity = 100000; 169 if (this.overFlowIndex == -1) { 170 this.overFlowIndex = children.length; 171 } 172 for (let index = 0; index < children.length; ++index) { 173 let child = children[index]; 174 if (index >= this.overFlowIndex) { 175 // Hide any child component that extends beyond the area of its parent component by placing it in a distant position. 176 child.layout({x: infinity, y: 0}); 177 continue; 178 } 179 child.layout({ x: currentX, y: 0 }) 180 let margin = child.getMargin(); 181 currentX += child.measureResult.width + margin.start + margin.end; 182 } 183 } 184 185 onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) { 186 let width = 0; 187 let height = 0; 188 this.overFlowIndex = -1; 189 // Assume that the component width cannot exceed 200 vp or the maximum constraint. 190 let maxWidth = Math.min(200, constraint.maxWidth as number); 191 for (let index = 0; index < children.length; ++index) { 192 let child = children[index]; 193 let childResult: MeasureResult = child.measure({ 194 minHeight: constraint.minHeight, 195 minWidth: constraint.minWidth, 196 maxWidth: constraint.maxWidth, 197 maxHeight: constraint.maxHeight 198 }) 199 let margin = child.getMargin(); 200 let newWidth = width + childResult.width + margin.start + margin.end; 201 if (newWidth > maxWidth) { 202 // Record the index of the component that should not be laid out. 203 this.overFlowIndex = index; 204 break; 205 } 206 // Accumulate the width and height of the parent component. 207 width = newWidth; 208 height = Math.max(height, childResult.height + margin.top + margin.bottom); 209 } 210 this.result.width = width; 211 this.result.height = height; 212 return this.result; 213 } 214 215 build() { 216 this.builder() 217 } 218} 219``` 220 221 222 223**Example 3** 224This example shows how to obtain the [FrameNode](../js-apis-arkui-frameNode.md#framenode) of a child component using **uniqueId** and change its size and background color using the FrameNode API. 225```ts 226import { FrameNode, NodeController } from '@kit.ArkUI'; 227@Entry 228@Component 229struct Index { 230 build() { 231 Column() { 232 CustomLayout() 233 } 234 } 235} 236 237class MyNodeController extends NodeController { 238 private rootNode: FrameNode | null = null; 239 makeNode(uiContext: UIContext): FrameNode | null { 240 this.rootNode = new FrameNode(uiContext) 241 return this.rootNode 242 } 243} 244 245@Component 246struct CustomLayout { 247 @Builder 248 childrenBuilder() { 249 ForEach([1, 2, 3], (index: number) => {// LazyForEach is not supported. 250 NodeContainer(new MyNodeController()) 251 }) 252 }; 253 254 @BuilderParam builder: () => void = this.childrenBuilder; 255 result: SizeResult = { 256 width: 0, 257 height: 0 258 }; 259 260 onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) { 261 let prev = 0; 262 children.forEach((child) => { 263 let pos = prev + 10; 264 prev = pos + child.measureResult.width 265 child.layout({ x: pos, y: 0 }) 266 }) 267 } 268 269 onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) { 270 let size = 100; 271 children.forEach((child) => { 272 console.log("child uniqueId: ", child.uniqueId) 273 const uiContext = this.getUIContext() 274 if (uiContext) { 275 let node: FrameNode | null = uiContext.getFrameNodeByUniqueId(child.uniqueId) // Obtain the FrameNode of the NodeContainer component. 276 if (node) { 277 node.getChild(0)!.commonAttribute.width(100) 278 node.getChild(0)!.commonAttribute.height(100) 279 node.getChild(0)!.commonAttribute.backgroundColor(Color.Pink) // Change the size and background color of the FrameNode. 280 } 281 } 282 child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }) 283 }) 284 this.result.width = 320; 285 this.result.height = 100; 286 return this.result; 287 } 288 289 build() { 290 this.builder() 291 } 292} 293``` 294 295 296## GeometryInfo<sup>10+</sup> 297 298Provides the parent component layout information. Inherits from [SizeResult](#sizeresult10). 299 300**Atomic service API**: This API can be used in atomic services since API version 11. 301 302**System capability**: SystemCapability.ArkUI.ArkUI.Full 303 304| Name | Type |Read-Only|Optional| Description | 305|-------------|-----------|------|------|---------------------| 306| borderWidth | [EdgeWidth](ts-types.md#edgewidths9) |No|No| Border width of the parent component.<br>Unit: vp | 307| margin | [Margin](ts-types.md#margin) | No|No|Margin of the parent component.<br>Unit: vp | 308| padding | [Padding](ts-types.md#padding) |No|No| Padding of the parent component.<br>Unit: vp| 309 310## Layoutable<sup>10+</sup> 311 312Provides the child component layout information. 313 314**Atomic service API**: This API can be used in atomic services since API version 11. 315 316**System capability**: SystemCapability.ArkUI.ArkUI.Full 317 318### Properties 319 320| Name | Type | Read-Only|Optional| Description | 321|--------------|---------------------------------- | ------|-----------------------------------------------------|---------------------| 322| measureResult| [MeasureResult](#measureresult10) | No|No| Measurement result of the child component.<br>**Atomic service API**: This API can be used in atomic services since API version 11.<br>Unit: vp | 323 324### layout 325 326layout(position: Position) 327 328Applies the specified position information to the child component. 329 330**Atomic service API**: This API can be used in atomic services since API version 11. 331 332**System capability**: SystemCapability.ArkUI.ArkUI.Full 333 334**Parameters** 335 336| Name | Type | Mandatory |Description | 337|-----------------|---------------------------------------------------------|---------------------|-------------| 338| position | [Position](ts-types.md#position) | Yes | Absolute position. | 339 340### getMargin<sup>12+</sup> 341 342getMargin() : DirectionalEdgesT\<number> 343 344Obtains the margin of the child component. 345 346**Atomic service API**: This API can be used in atomic services since API version 12. 347 348**System capability**: SystemCapability.ArkUI.ArkUI.Full 349 350**Return value** 351 352| Type | Description | 353|------------------------------------|---------------------------------------------| 354| [DirectionalEdgesT<number>](#directionaledgestt12) | Margin of the child component. | 355 356 ### getPadding<sup>12+</sup> 357 358getPadding() : DirectionalEdgesT\<number> 359 360 Obtains the padding of the child component. 361 362**Atomic service API**: This API can be used in atomic services since API version 12. 363 364**System capability**: SystemCapability.ArkUI.ArkUI.Full 365 366 **Return value** 367 368| Type | Description | 369|------------------------------------|---------------------------------------------| 370| [DirectionalEdgesT<number>](#directionaledgestt12) | Padding of the child component. | 371 372### getBorderWidth<sup>12+</sup> 373 374getBorderWidth() : DirectionalEdgesT\<number> 375 376Obtains the border width of the child component. 377 378**Atomic service API**: This API can be used in atomic services since API version 12. 379 380**System capability**: SystemCapability.ArkUI.ArkUI.Full 381 382**Return value** 383 384| Type | Description | 385|------------------------------------|---------------------------------------------| 386| [DirectionalEdgesT<number>](#directionaledgestt12) | Border width of the child component. | 387 388## Measurable<sup>10+</sup> 389 390Provides the child component position information. 391 392**Atomic service API**: This API can be used in atomic services since API version 11. 393 394**System capability**: SystemCapability.ArkUI.ArkUI.Full 395 396### Name 397 398**Atomic service API**: This API can be used in atomic services since API version 18. 399 400**System capability**: SystemCapability.ArkUI.ArkUI.Full 401 402| Name | Type | Mandatory | Description | 403|--------------|---------------------------------- | -----------------------------------------------|---------------------| 404| uniqueId<sup>18+</sup>| number | No| Unique ID that the system assigns to the child component.| 405 406### measure 407 408 measure(constraint: ConstraintSizeOptions) : MeasureResult 409 410 Applies the size constraint to the child component. 411 412 **Atomic service API**: This API can be used in atomic services since API version 11. 413 414 **System capability**: SystemCapability.ArkUI.ArkUI.Full 415 416 417**Parameters** 418 419| Name | Type | Mandatory |Description | 420|-----------------|---------------------------------------------------------|---------------------|-------------| 421| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Yes | Size constraint. | 422 423**Return value** 424 425 | Type | Description | 426 |------------------------------------|-------------------------| 427 |[MeasureResult](#measureresult10) | Provides the measurement result of the component. | 428 429 ### getMargin<sup>12+</sup> 430 431 getMargin() : DirectionalEdgesT\<number\> 432 433 Obtains the margin of the child component. 434 435**Atomic service API**: This API can be used in atomic services since API version 12. 436 437**System capability**: SystemCapability.ArkUI.ArkUI.Full 438 439**Return value** 440 441 | Type | Description | 442 |------------------------------------|-------------------------| 443 |[DirectionalEdgesT<number>](#directionaledgestt12) | Margin of the child component. | 444 445### getPadding<sup>12+</sup> 446 447getPadding() : DirectionalEdgesT\<number\> 448 449Obtains the padding of the child component. 450 451**Atomic service API**: This API can be used in atomic services since API version 12. 452 453**System capability**: SystemCapability.ArkUI.ArkUI.Full 454 455**Return value** 456 457 | Type | Description | 458 |------------------------------------|-------------------------| 459 |[DirectionalEdgesT<number>](#directionaledgestt12) | Padding of the child component. | 460 461 ### getBorderWidth<sup>12+</sup> 462 463getBorderWidth() : DirectionalEdgesT\<number\> 464 465Obtains the border width of the child component. 466 467**Atomic service API**: This API can be used in atomic services since API version 12. 468 469**System capability**: SystemCapability.ArkUI.ArkUI.Full 470 471**Return value** 472 473 | Type | Description | 474 |------------------------------------|-------------------------| 475 |[DirectionalEdgesT<number>](#directionaledgestt12) | Border width of the child component.| 476 477 478## MeasureResult<sup>10+</sup> 479 480Provides the measurement result of the component. This API inherites from [SizeResult] (#sizeresult10). 481 482**Atomic service API**: This API can be used in atomic services since API version 11. 483 484**System capability**: SystemCapability.ArkUI.ArkUI.Full 485 486## SizeResult<sup>10+</sup> 487 488Provides the component size information. 489 490**Atomic service API**: This API can be used in atomic services since API version 11. 491 492**System capability**: SystemCapability.ArkUI.ArkUI.Full 493 494| Name | Type |Read-Only|Optional| Description | 495|--------|--------|------|------|-------| 496| width | number | No|No|Width obtained from the measurement result.<br>Unit: vp| 497| height | number | No|No|Height obtained from the measurement result.<br>Unit: vp| 498 499## DirectionalEdgesT\<T><sup>12+</sup> 500 501Defines the directional edges. 502 503**Widget capability**: This API can be used in ArkTS widgets since API version 12. 504 505**Atomic service API**: This API can be used in atomic services since API version 12. 506 507**System capability**: SystemCapability.ArkUI.ArkUI.Full 508 509| Name | Type|Read-Only|Optional| Description | 510| ------ | ---- |------|------| ---------------- | 511| start | T |No|No| Start edge. It is the left edge if the direction is left-to-right and the right edge if the direction is right-to-left.| 512| end | T | No|No|End edge. It is the right edge if the direction is left-to-right and the left edge if the direction is right-to-left.| 513| top | T | No|No|Top edge.| 514| bottom | T | No|No|Top edge.| 515 516> **NOTE** 517> 518>- The custom layout does not support the LazyForEach syntax. 519>- When a custom layout is created in builder mode, only **this.builder()** is allowed in the **build()** method of a custom component, as shown in the recommended usage in the example below. 520>- The size parameters of the parent component (custom component), except **aspectRatio**, are at a lower priority than those specified by **onMeasureSize**. 521>- The position parameters of the child component, except **offset**, **position**, and **markAnchor**, are at a lower priority than those specified by **onPlaceChildren**, and do not take effect. 522>- When using the custom layout method, you must call **onMeasureSize** and **onPlaceChildren** at the same time for the layout to display properly. 523 524## onLayout<sup>(deprecated)</sup> 525 526onLayout?(children: Array<LayoutChild>, constraint: ConstraintSizeOptions): void 527 528Invoked when the custom component lays out its child components. Through this callback the component receives its child component layout information and size constraint from the ArkUI framework. State variables should not be changed in this callback. 529 530This API is supported since API version 9 and deprecated since API version 10. You are advised to use [onPlaceChildren](#onplacechildren10) instead. 531 532**Widget capability**: This API can be used in ArkTS widgets since API version 9. 533 534**System capability**: SystemCapability.ArkUI.ArkUI.Full 535 536**Parameters** 537 538| Name | Type | Mandatory|Description | 539|------------|------------------------------------------------------------|------|------------------| 540| children | Array<[LayoutChild](#layoutchilddeprecated)> | Yes | Child component layout information. | 541| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Yes |Size constraint of the parent component.| 542 543## onMeasure<sup>(deprecated)</sup> 544 545onMeasure?(children: Array<LayoutChild>, constraint: ConstraintSizeOptions): void 546 547Invoked when the custom component needs to determine its size. Through this callback the component receives its child component layout information and size constraint from the ArkUI framework. State variables should not be changed in this callback. 548 549This API is supported since API version 9 and deprecated since API version 10. You are advised to use [onMeasureSize](#onmeasuresize10) instead. 550 551**Widget capability**: This API can be used in ArkTS widgets since API version 9. 552 553**System capability**: SystemCapability.ArkUI.ArkUI.Full 554 555**Parameters** 556 557| Name | Type |Mandatory| Description | 558|------------|------------------------------------------------------------|------|------------------| 559| children | Array<[LayoutChild](#layoutchilddeprecated)> | Yes |Child component layout information. | 560| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Yes |Size constraint of the parent component.| 561 562## LayoutChild<sup>(deprecated)</sup> 563 564Child component layout information. 565 566This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets. 567 568**Widget capability**: This API can be used in ArkTS widgets since API version 9. 569 570**System capability**: SystemCapability.ArkUI.ArkUI.Full 571 572| Name | Type | Read-Only|Optional|Description | 573| ---------- | ------------------------------------------------------------ | ------|------|-------------------------------------- | 574| name | string | No|No|Name of the child component. | 575| id | string | No|No|ID of the child component. | 576| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | No|No|Constraint size of the child component. | 577| borderInfo | [LayoutBorderInfo](#layoutborderinfodeprecated) | No|No|Provides the border information of the child component. | 578| position | [Position](ts-types.md#position) | No|No|Position coordinates of the child component. | 579| measure | (childConstraint: [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)) => void |No|No| Method called to apply the size constraint to the child component.| 580| layout | (LayoutInfo: [LayoutInfo](#layoutinfodeprecated)) => void | No|No|Method called to apply the specified position information to the child component.| 581 582## LayoutBorderInfo<sup>(deprecated)</sup> 583 584Provides the border information of the child component. 585 586This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets. 587 588**Widget capability**: This API can be used in ArkTS widgets since API version 9. 589 590**System capability**: SystemCapability.ArkUI.ArkUI.Full 591 592| Name | Type | Read-Only|Optional|Description | 593|-------------|--------------------------------------|------|------|-------------------------| 594| borderWidth | [EdgeWidths](ts-types.md#edgewidths9) | No|No|Edge widths in different directions of the component.| 595| margin | [Margin](ts-types.md#margin) | No|No|Margins in different directions of the component. | 596| padding | [Padding](ts-types.md#padding) | No|No|Paddings in different directions of the component. | 597 598## LayoutInfo<sup>(deprecated)</sup> 599 600Provides the layout information of the child component. 601 602This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets. 603 604**Widget capability**: This API can be used in ArkTS widgets since API version 9. 605 606**System capability**: SystemCapability.ArkUI.ArkUI.Full 607 608| Name | Type | Read-Only|Optional|Description | 609| ---------- | ---------------------------------------------------------- | ------|------|---------------- | 610| position | [Position](ts-types.md#position) |No|No| Position coordinates of the child component.| 611| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | No|No|Constraint size of the child component.| 612 613The layout can be modified through **layout**. 614```ts 615// xxx.ets 616@Entry 617@Component 618struct Index { 619 build() { 620 Column() { 621 CustomLayout() { 622 ForEach([1, 2, 3], (index: number) => { 623 Text('Sub' + index) 624 .fontSize(30) 625 .borderWidth(2) 626 }) 627 } 628 } 629 } 630} 631 632 633@Component 634struct CustomLayout { 635 @Builder 636 doNothingBuilder() { 637 }; 638 639 @BuilderParam builder: () => void = this.doNothingBuilder; 640 641 onLayout(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) { 642 let pos = 0; 643 children.forEach((child) => { 644 child.layout({ position: { x: pos, y: pos }, constraint: constraint }) 645 pos += 70; 646 }) 647 } 648 649 onMeasure(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) { 650 let size = 100; 651 children.forEach((child) => { 652 child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }) 653 size += 50; 654 }) 655 } 656 657 build() { 658 this.builder() 659 } 660} 661``` 662 663 664