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&lt;Layoutable&gt;, 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**System capability**: SystemCapability.ArkUI.ArkUI.Full
16
17**Atomic service API**: This API can be used in atomic services since API version 11.
18
19**Parameters**
20
21| Name           | Type                                                        | Description              |
22|----------------|------------------------------------------------------------|------------------|
23| selfLayoutInfo | [GeometryInfo](#geometryinfo10)                            | Layout information of the parent component.        |
24| children       | Array&lt;[Layoutable](#layoutable10)&gt;                   | Child component layout information.        |
25| constraint     | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Size constraint of the parent component.|
26
27## onMeasureSize<sup>10+</sup>
28
29onMeasureSize?(selfLayoutInfo: GeometryInfo, children: Array&lt;Measurable&gt;, constraint: ConstraintSizeOptions): SizeResult
30
31Invoked 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.
32
33**System capability**: SystemCapability.ArkUI.ArkUI.Full
34
35**Atomic service API**: This API can be used in atomic services since API version 11.
36
37**Parameters**
38
39| Name        | Type                                                      | Description                                                        |
40| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------ |
41| selfLayoutInfo | [GeometryInfo](#geometryinfo10)                            | Layout information of the parent component.                                            |
42| children       | Array&lt;[Measurable](#measurable10)&gt;                   | Child component layout information.<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.|
43| constraint     | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Size constraint of the parent component.                                      |
44
45**Return value**
46
47| Type                       | Description          |
48| --------------------------- | -------------- |
49| [SizeResult](#sizeresult10) | Component size information.|
50
51## GeometryInfo<sup>10+</sup>
52
53Provides the parent component layout information. Inherits from [SizeResult](#sizeresult10).
54
55**System capability**: SystemCapability.ArkUI.ArkUI.Full
56
57**Atomic service API**: This API can be used in atomic services since API version 11.
58
59| Name         | Type     | Description                 |
60|-------------|-----------|---------------------|
61| borderWidth | [EdgeWidth](ts-types.md#edgewidths9) | Border width of the parent component.<br>Unit: vp           |
62| margin      | [Margin](ts-types.md#margin)       | Margin of the parent component.<br>Unit: vp      |
63| padding     | [Padding](ts-types.md#padding)   | Padding of the parent component.<br>Unit: vp|
64| width  | number | Width obtained from the measurement result.<br>Unit: vp<br> **NOTE**<br>If the value is empty, the component width in percentage is returned.|
65| height | number | Height obtained from the measurement result.<br>Unit: vp<br> **NOTE**<br>If the value is empty, the component height in percentage is returned.|
66
67
68## Layoutable<sup>10+</sup>
69
70Provides the child component layout information.
71
72**System capability**: SystemCapability.ArkUI.ArkUI.Full
73
74### Name
75
76| Name        | Type      | Mandatory     |  Description                                                     |
77|--------------|---------------------------------- | -----------------------------------------------|---------------------|
78| measureResult| [MeasureResult](#measureresult10)      |   Yes| Measurement result of the child component. Inherits from [SizeResult](#sizeresult10).<br>**Atomic service API**: This API can be used in atomic services since API version 11.<br>Unit: vp    |
79
80
81### layout
82
83layout(position: Position)
84
85Applies the specified position information to the child component.
86
87**Atomic service API**: This API can be used in atomic services since API version 11.
88
89**System capability**: SystemCapability.ArkUI.ArkUI.Full
90
91**Parameters**
92
93| Name        | Type                                                   | Mandatory                |Description        |
94|-----------------|---------------------------------------------------------|---------------------|-------------|
95|   position      | [Position](ts-types.md#position)                        | Yes                 |   Position.  |
96
97### getMargin<sup>12+</sup>
98
99getMargin() : DirectionalEdgesT\<number>
100
101Obtains the margin of the child component.
102
103**Return value**
104
105| Type                         | Description                                       |
106|------------------------------------|---------------------------------------------|
107| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  Margin of the child component.  |
108
109 ### getPadding<sup>12+</sup>
110
111getPadding() : DirectionalEdgesT\<number>
112
113 Obtains the padding of the child component.
114
115 **Return value**
116
117| Type                         | Description                                       |
118|------------------------------------|---------------------------------------------|
119| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  Padding of the child component. |
120
121### getBorderWidth<sup>12+</sup>
122
123getBorderWidth() : DirectionalEdgesT\<number>
124
125Obtains the border width of the child component.
126
127**Return value**
128
129| Type                         | Description                                       |
130|------------------------------------|---------------------------------------------|
131| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  Border width of the child component. |
132
133## Measurable<sup>10+</sup>
134
135Provides the child component position information.
136
137**System capability**: SystemCapability.ArkUI.ArkUI.Full
138
139**Atomic service API**: This API can be used in atomic services since API version 11.
140
141### measure
142
143 measure(constraint: ConstraintSizeOptions) : MeasureResult
144
145 Applies the size constraint to the child component.
146
147 **System capability**: SystemCapability.ArkUI.ArkUI.Full
148
149**Atomic service API**: This API can be used in atomic services since API version 11.
150
151**Parameters**
152
153| Name        | Type                                                   | Mandatory                |Description        |
154|-----------------|---------------------------------------------------------|---------------------|-------------|
155|   constraint    | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)  | Yes           |   Size constraint. |
156
157**Return value**
158
159 | Type                              | Description                    |
160 |------------------------------------|-------------------------|
161 |[MeasureResult](#measureresult10)   | Provides the measurement result of the component.  |
162
163 ### getMargin<sup>12+</sup>
164
165 getMargin() : DirectionalEdgesT\<number\>
166
167 Obtains the padding of the child component.
168
169**System capability**: SystemCapability.ArkUI.ArkUI.Full
170
171**Atomic service API**: This API can be used in atomic services since API version 12.
172
173**Return value**
174
175 | Type                              | Description                    |
176 |------------------------------------|-------------------------|
177 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | Margin of the child component.  |
178
179### getPadding<sup>12+</sup>
180
181getPadding() : DirectionalEdgesT\<number\>
182
183Obtains the padding of the child component.
184
185**System capability**: SystemCapability.ArkUI.ArkUI.Full
186
187**Atomic service API**: This API can be used in atomic services since API version 12.
188
189**Return value**
190
191 | Type                              | Description                    |
192 |------------------------------------|-------------------------|
193 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | Padding of the child component.  |
194
195 ### getBorderWidth<sup>12+</sup>
196
197getBorderWidth() : DirectionalEdgesT\<number\>
198
199Obtains the border widthof the child component.
200
201**System capability**: SystemCapability.ArkUI.ArkUI.Full
202
203**Atomic service API**: This API can be used in atomic services since API version 12.
204
205**Return value**
206
207 | Type                              | Description                    |
208 |------------------------------------|-------------------------|
209 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | Border width of the child component.|
210
211
212## MeasureResult<sup>10+</sup>
213
214Provides the measurement result of the component.
215
216**System capability**: SystemCapability.ArkUI.ArkUI.Full
217
218**Atomic service API**: This API can be used in atomic services since API version 11.
219
220| Name    | Type  | Description   |
221|--------|--------|-------|
222| width  | number | Width obtained from the measurement result.<br>Unit: vp|
223| height | number | Height obtained from the measurement result.<br>Unit: vp|
224
225
226## SizeResult<sup>10+</sup>
227
228Provides the component size information.
229
230**System capability**: SystemCapability.ArkUI.ArkUI.Full
231
232**Atomic service API**: This API can be used in atomic services since API version 11.
233
234| Name    | Type  | Description   |
235|--------|--------|-------|
236| width  | number | Width obtained from the measurement result.<br>Unit: vp|
237| height | number | Height obtained from the measurement result.<br>Unit: vp|
238
239## DirectionalEdgesT\<T><sup>12+</sup>
240
241Defines the directional edges.
242
243**System capability**: SystemCapability.ArkUI.ArkUI.Full
244
245**Widget capability**: This API can be used in ArkTS widgets since API version 12.
246
247| Name  | Type| Description            |
248| ------ | ---- | ---------------- |
249| start   | T    | 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.|
250| end    | T    | 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.|
251| top  | T    | Top edge.|
252| bottom | T    | Top edge.|
253
254> **NOTE**
255>
256>- The custom layout does not support the LazyForEach syntax.
257>- 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.
258>- The size parameters of the parent component (custom component), except **aspectRatio**, are at a lower priority than those specified by **onMeasureSize**.
259>- 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.
260>- When using the custom layout method, you must call **onMeasureSize** and **onPlaceChildren** at the same time for the layout to display properly.
261
262**Example 1**
263This example demonstrates how to customize a layout.
264```
265// xxx.ets
266@Entry
267@Component
268struct Index {
269  build() {
270    Column() {
271      CustomLayout({ builder: ColumnChildren })
272    }
273  }
274}
275
276@Builder
277function ColumnChildren() {
278  ForEach([1, 2, 3], (index: number) => {// LazyForEach is not supported.
279    Text('S' + index)
280      .fontSize(30)
281      .width(100)
282      .height(100)
283      .borderWidth(2)
284      .offset({ x: 10, y: 20 })
285  })
286}
287
288@Component
289struct CustomLayout {
290  @Builder
291  doNothingBuilder() {
292  };
293
294  @BuilderParam builder: () => void = this.doNothingBuilder;
295  @State startSize: number = 100;
296  result: SizeResult = {
297    width: 0,
298    height: 0
299  };
300
301  onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) {
302    let startPos = 300;
303    children.forEach((child) => {
304      let pos = startPos - child.measureResult.height;
305      child.layout({ x: pos, y: pos })
306    })
307  }
308
309  onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) {
310    let size = 100;
311    children.forEach((child) => {
312      let result: MeasureResult = child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size })
313      size += result.width / 2
314      ;
315    })
316    this.result.width = 100;
317    this.result.height = 400;
318    return this.result;
319  }
320
321  build() {
322    this.builder()
323  }
324}
325```
326
327![custom_layout10.png](figures/custom_layout10.png)
328
329**Example 2**
330This example shows how to determine whether a component participates in layout calculation based on its position.
331```
332// xxx.ets
333@Entry
334@Component
335struct Index {
336  build() {
337    Column() {
338      CustomLayout({ builder: ColumnChildren })
339    }
340    .justifyContent(FlexAlign.Center)
341    .width("100%")
342    .height("100%")
343  }
344}
345
346@Builder
347function ColumnChildren() {
348  ForEach([1, 2, 3], (item: number, index: number) => { // LazyForEach is not supported.
349    Text('S' + item)
350      .fontSize(20)
351      .width(60 + 10 * index)
352      .height(100)
353      .borderWidth(2)
354      .margin({ left:10 })
355      .padding(10)
356  })
357}
358
359@Component
360struct CustomLayout {
361  // Lay out only one row, and hide child components that are too large for the available space.
362  @Builder
363  doNothingBuilder() {
364  };
365
366  @BuilderParam builder: () => void = this.doNothingBuilder;
367  result: SizeResult = {
368    width: 0,
369    height: 0
370  };
371  overFlowIndex: number = -1;
372
373  onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) {
374    let currentX = 0;
375    let infinity = 100000;
376    if (this.overFlowIndex == -1) {
377      this.overFlowIndex = children.length;
378    }
379    for (let index = 0; index < children.length; ++index) {
380      let child = children[index];
381      if (index >= this.overFlowIndex) {
382        // Hide any child component that extends beyond the area of its parent component by placing it in a distant position.
383        child.layout({x: infinity, y: 0});
384        continue;
385      }
386      child.layout({ x: currentX, y: 0 })
387      let margin = child.getMargin();
388      currentX += child.measureResult.width + margin.start + margin.end;
389    }
390  }
391
392  onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) {
393    let width = 0;
394    let height = 0;
395    this.overFlowIndex = -1;
396    // Assume that the component width cannot exceed 200 vp or the maximum constraint.
397    let maxWidth = Math.min(200, constraint.maxWidth as number);
398    for (let index = 0; index < children.length; ++index) {
399      let child = children[index];
400      let childResult: MeasureResult = child.measure({
401          minHeight: constraint.minHeight,
402          minWidth: constraint.minWidth,
403          maxWidth: constraint.maxWidth,
404          maxHeight: constraint.maxHeight
405      })
406      let margin = child.getMargin();
407      let newWidth = width + childResult.width + margin.start + margin.end;
408      if (newWidth > maxWidth) {
409        // Record the index of the component that should not be laid out.
410        this.overFlowIndex = index;
411        break;
412      }
413      // Accumulate the width and height of the parent component.
414      width = newWidth;
415      height = Math.max(height, childResult.height + margin.top + margin.bottom);
416    }
417    this.result.width = width;
418    this.result.height = height;
419    return this.result;
420  }
421
422  build() {
423    this.builder()
424  }
425}
426```
427
428![custom_layout_demo2.png](figures/custom_layout_demo2.png)
429
430## onLayout<sup>(deprecated)</sup>
431
432onLayout?(children: Array&lt;LayoutChild&gt;, constraint: ConstraintSizeOptions): void
433
434Invoked 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.
435
436This API is supported since API version 9 and deprecated since API version 10. You are advised to use [onPlaceChildren](#onplacechildren10) instead.
437
438**Parameters**
439
440| Name       | Type                                                        | Description              |
441|------------|------------------------------------------------------------|------------------|
442| children   | Array&lt;[LayoutChild](#layoutchilddeprecated)&gt;                  | Child component layout information.        |
443| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Size constraint of the parent component.|
444
445## onMeasure<sup>(deprecated)</sup>
446
447onMeasure?(children: Array&lt;LayoutChild&gt;, constraint: ConstraintSizeOptions): void
448
449Invoked 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.
450
451This API is supported since API version 9 and deprecated since API version 10. You are advised to use [onMeasureSize](#onmeasuresize10) instead.
452
453**Parameters**
454
455| Name       | Type                                                        | Description              |
456|------------|------------------------------------------------------------|------------------|
457| children   | Array&lt;[LayoutChild](#layoutchilddeprecated)&gt;                  | Child component layout information.        |
458| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Size constraint of the parent component.|
459
460## LayoutChild<sup>(deprecated)</sup>
461
462Child component layout information.
463
464This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets.
465
466
467| Name      | Type                                                    | Description                                  |
468| ---------- | ------------------------------------------------------------ | -------------------------------------- |
469| name       | string                                                       | Name of the child component.                          |
470| id         | string                                                       | ID of the child component.                            |
471| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)   | Constraint size of the child component.                      |
472| borderInfo | [LayoutBorderInfo](#layoutborderinfodeprecated)              | Provides the border information of the child component.                    |
473| position   | [Position](ts-types.md#position)                             | Position coordinates of the child component.                      |
474| measure    | (childConstraint: [ConstraintSizeOptions](ts-types.md#constraintsizeoptions))&nbsp;=&gt;&nbsp;void | Method called to apply the size constraint to the child component.|
475| layout     | (LayoutInfo: [LayoutInfo](#layoutinfodeprecated))&nbsp;=&gt;&nbsp;void | Method called to apply the specified position information to the child component.|
476
477## LayoutBorderInfo<sup>(deprecated)</sup>
478
479Provides the border information of the child component.
480
481This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets.
482
483| Name         | Type                                | Description                     |
484|-------------|--------------------------------------|-------------------------|
485| borderWidth | [EdgeWidths](ts-types.md#edgewidths9) | Edge widths in different directions of the component.|
486| margin      | [Margin](ts-types.md#margin)         | Margins in different directions of the component.  |
487| padding     | [Padding](ts-types.md#padding)       | Paddings in different directions of the component.  |
488
489## LayoutInfo<sup>(deprecated)</sup>
490
491Provides the layout information of the child component.
492
493This API is supported since API version 9 and deprecated since API version 10. It is supported in ArkTS widgets.
494
495| Name      | Type                                                  | Description            |
496| ---------- | ---------------------------------------------------------- | ---------------- |
497| position   | [Position](ts-types.md#position)                           | Position coordinates of the child component.|
498| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Constraint size of the child component.|
499
500The layout can be modified through **layout**.
501```ts
502// xxx.ets
503@Entry
504@Component
505struct Index {
506  build() {
507    Column() {
508      CustomLayout() {
509        ForEach([1, 2, 3], (index: number) => {
510          Text('Sub' + index)
511            .fontSize(30)
512            .borderWidth(2)
513        })
514      }
515    }
516  }
517}
518
519
520@Component
521struct CustomLayout {
522  @Builder
523  doNothingBuilder() {
524  };
525
526  @BuilderParam builder: () => void = this.doNothingBuilder;
527
528  onLayout(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) {
529    let pos = 0;
530    children.forEach((child) => {
531      child.layout({ position: { x: pos, y: pos }, constraint: constraint })
532      pos += 70;
533    })
534  }
535
536  onMeasure(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) {
537    let size = 100;
538    children.forEach((child) => {
539      child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size })
540      size += 50;
541    })
542  }
543
544  build() {
545    this.builder()
546  }
547}
548```
549
550![en-us_image_0000001511900496](figures/en-us_image_0000001511900496.png)
551