• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 自定义组件的自定义布局
2
3自定义组件的自定义布局用于通过数据计算的方式布局自定义组件内的子组件。
4
5> **说明:**
6>
7> 本模块首批接口从API version 9开始支持,后续版本的新增接口,采用上角标单独标记接口的起始版本。
8
9## onPlaceChildren<sup>10+</sup>
10
11onPlaceChildren?(selfLayoutInfo: GeometryInfo, children: Array&lt;Layoutable&gt;, constraint: ConstraintSizeOptions):void
12
13ArkUI框架会在自定义组件布局时,将该自定义组件的子节点自身的尺寸范围通过onPlaceChildren传递给该自定义组件。不允许在onPlaceChildren函数中改变状态变量。
14
15**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
16
17**系统能力:** SystemCapability.ArkUI.ArkUI.Full
18
19**参数:**
20
21| 参数名            | 类型                                                         |必填| 说明               |
22|----------------|------------------------------------------------------------|---|------------------|
23| selfLayoutInfo | [GeometryInfo](#geometryinfo10)                            |是 |测量后的自身布局信息。         |
24| children       | Array&lt;[Layoutable](#layoutable10)&gt;                   |是 |测量后的子组件布局信息。         |
25| constraint     | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) |是 |父组件constraint信息。 |
26
27**示例:**
28
29示例请参考[自定义布局代码示例](#onmeasuresize10)。
30
31## onMeasureSize<sup>10+</sup>
32
33onMeasureSize?(selfLayoutInfo: GeometryInfo, children: Array&lt;Measurable&gt;, constraint: ConstraintSizeOptions): SizeResult
34
35ArkUI框架会在自定义组件确定尺寸时,将该自定义组件的节点信息和尺寸范围通过onMeasureSize传递给该开发者。不允许在onMeasureSize函数中改变状态变量。
36
37**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
38
39**系统能力:** SystemCapability.ArkUI.ArkUI.Full
40
41**参数:**
42
43| 参数名         | 类型                                                       | 必填|说明                                                         |
44| -------------- | ---------------------------------------------------------- | ---|------------------------------------------------------------ |
45| selfLayoutInfo | [GeometryInfo](#geometryinfo10)                            | 是|测量后的自身布局信息。  <br/>**说明:** <br/>第一次布局时以自身设置的属性为准。                                    |
46| children       | Array&lt;[Measurable](#measurable10)&gt;                   | 是|测量后的子组件布局信息。<br/>**说明:** <br/>如果没有设置子组件的布局信息,子组件会维持上一次的布局信息,当子组件从来没有设置过尺寸时,尺寸默认为0。 |
47| constraint     | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 是|父组件constraint信息。                                       |
48
49**返回值:**
50
51| 类型                        | 说明           |
52| --------------------------- | -------------- |
53| [SizeResult](#sizeresult10) | 组件尺寸信息。 |
54
55**示例一:**
56自定义布局代码示例。
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的写法
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![custom_layout10.png](figures/custom_layout10.png)
121
122**示例二:**
123通过组件的位置灵活判断是否参与布局计算。
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的写法
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  // 只布局一行,如果布局空间不够的子组件不显示的demo
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        // 如果子组件超出父组件范围,将它布局到较偏的位置,达到不显示的目的
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    // 假定该组件的宽度不能超过200vp,也不能超过最大约束
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        // 记录不该布局的组件的下标
203        this.overFlowIndex = index;
204        break;
205      }
206      // 累积父组件的宽度和高度
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![custom_layout_demo2.png](figures/custom_layout_demo2.png)
222
223**示例三:**
224通过uniqueId获取子组件的[FrameNode](../js-apis-arkui-frameNode.md#framenode)  ,并调用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的写法
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) // 获取NodeContainer组件的FrameNode
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) // 修改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![custom_layout_demo3.jpg](figures/custom_layout_demo3.jpg)
295
296## GeometryInfo<sup>10+</sup>
297
298父组件布局信息,继承自[SizeResult](#sizeresult10)。
299
300**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
301
302**系统能力:** SystemCapability.ArkUI.ArkUI.Full
303
304| 属性          | 类型      |只读|可选| 说明                  |
305|-------------|-----------|------|------|---------------------|
306| borderWidth | [EdgeWidth](ts-types.md#edgewidths9) |否|否| 父组件边框宽度。<br>单位:vp            |
307| margin      | [Margin](ts-types.md#margin)       | 否|否|父组件margin信息。 <br>单位:vp       |
308| padding     | [Padding](ts-types.md#padding)   |否|否| 父组件padding信息。<br>单位:vp |
309
310## Layoutable<sup>10+</sup>
311
312子组件布局信息。
313
314**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
315
316**系统能力:** SystemCapability.ArkUI.ArkUI.Full
317
318### 属性
319
320| 名称         | 类型       | 只读|可选|  说明                                                      |
321|--------------|---------------------------------- | ------|-----------------------------------------------------|---------------------|
322| measureResult| [MeasureResult](#measureresult10)      |   否|否| 子组件测量后的尺寸信息。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。<br>单位:vp     |
323
324### layout
325
326layout(position: Position)
327
328调用此方法对子组件的位置信息进行限制。
329
330**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
331
332**系统能力:** SystemCapability.ArkUI.ArkUI.Full
333
334**参数:**
335
336| 参数名         | 类型                                                    | 必填                 |说明         |
337|-----------------|---------------------------------------------------------|---------------------|-------------|
338|   position      | [Position](ts-types.md#position)                        | 是                  |   绝对位置。   |
339
340### getMargin<sup>12+</sup>
341
342getMargin() : DirectionalEdgesT\<number>
343
344调用此方法获得子组件的margin信息。
345
346**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
347
348**系统能力:** SystemCapability.ArkUI.ArkUI.Full
349
350**返回值:**
351
352| 类型                          | 说明                                        |
353|------------------------------------|---------------------------------------------|
354| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  子组件的margin信息。   |
355
356 ### getPadding<sup>12+</sup>
357
358getPadding() : DirectionalEdgesT\<number>
359
360 调用此方法获得子组件的padding信息。
361
362**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
363
364**系统能力:** SystemCapability.ArkUI.ArkUI.Full
365
366 **返回值:**
367
368| 类型                          | 说明                                        |
369|------------------------------------|---------------------------------------------|
370| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  子组件的padding信息。  |
371
372### getBorderWidth<sup>12+</sup>
373
374getBorderWidth() : DirectionalEdgesT\<number>
375
376调用此方法获得子组件的borderWidth信息。
377
378**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
379
380**系统能力:** SystemCapability.ArkUI.ArkUI.Full
381
382**返回值:**
383
384| 类型                          | 说明                                        |
385|------------------------------------|---------------------------------------------|
386| [DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  |  子组件的borderWidth信息。  |
387
388## Measurable<sup>10+</sup>
389
390子组件位置信息。
391
392**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
393
394**系统能力:** SystemCapability.ArkUI.ArkUI.Full
395
396### 属性
397
398**原子化服务API:** 从API version 18开始,该接口支持在原子化服务中使用。
399
400**系统能力:** SystemCapability.ArkUI.ArkUI.Full
401
402| 名称         | 类型       | 必填      |  说明                                                      |
403|--------------|---------------------------------- | -----------------------------------------------|---------------------|
404| uniqueId<sup>18+</sup>| number | 否 | 系统为子组件分配的唯一标识UniqueID。|
405
406### measure
407
408 measure(constraint: ConstraintSizeOptions) : MeasureResult
409
410 调用此方法对子组件的尺寸范围进行限制。
411
412 **原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
413
414 **系统能力:** SystemCapability.ArkUI.ArkUI.Full
415
416
417**参数:**
418
419| 参数名         | 类型                                                    | 必填                 |说明         |
420|-----------------|---------------------------------------------------------|---------------------|-------------|
421|   constraint    | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)  | 是            |   约束尺寸。  |
422
423**返回值:**
424
425 | 类型                               | 说明                     |
426 |------------------------------------|-------------------------|
427 |[MeasureResult](#measureresult10)   | 测量后的组件布局信息。   |
428
429 ### getMargin<sup>12+</sup>
430
431 getMargin() : DirectionalEdgesT\<number\>
432
433 获取子组件的margin信息。
434
435**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
436
437**系统能力:** SystemCapability.ArkUI.ArkUI.Full
438
439**返回值:**
440
441 | 类型                               | 说明                     |
442 |------------------------------------|-------------------------|
443 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | 子组件的margin信息。   |
444
445### getPadding<sup>12+</sup>
446
447getPadding() : DirectionalEdgesT\<number\>
448
449获取子组件的padding信息。
450
451**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
452
453**系统能力:** SystemCapability.ArkUI.ArkUI.Full
454
455**返回值:**
456
457 | 类型                               | 说明                     |
458 |------------------------------------|-------------------------|
459 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | 子组件的padding信息。   |
460
461 ### getBorderWidth<sup>12+</sup>
462
463getBorderWidth() : DirectionalEdgesT\<number\>
464
465获取子组件的borderWidth信息。
466
467**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
468
469**系统能力:** SystemCapability.ArkUI.ArkUI.Full
470
471**返回值:**
472
473 | 类型                               | 说明                     |
474 |------------------------------------|-------------------------|
475 |[DirectionalEdgesT&lt;number&gt;](#directionaledgestt12)  | 子组件的borderWidth信息。|
476
477
478## MeasureResult<sup>10+</sup>
479
480测量后的组件布局信息。继承自[SizeResult](#sizeresult10)。
481
482**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
483
484**系统能力:** SystemCapability.ArkUI.ArkUI.Full
485
486## SizeResult<sup>10+</sup>
487
488组件尺寸信息。
489
490**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
491
492**系统能力:** SystemCapability.ArkUI.ArkUI.Full
493
494| 名称     | 类型   |只读|可选| 说明    |
495|--------|--------|------|------|-------|
496| width  | number | 否|否|测量后的宽。<br>单位:vp |
497| height | number | 否|否|测量后的高。<br>单位:vp |
498
499## DirectionalEdgesT\<T><sup>12+</sup>
500
501全球化的边缘属性。
502
503**卡片能力:** 从API version 12开始,该接口支持在ArkTS卡片中使用。
504
505**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
506
507**系统能力:** SystemCapability.ArkUI.ArkUI.Full
508
509| 名称   | 类型 |只读|可选| 说明             |
510| ------ | ---- |------|------| ---------------- |
511| start   | T    |否|否| 起始边缘的属性。在LTR的方向下,为左边缘,在RTL的方向下,为右边缘。 |
512| end    | T    | 否|否|终止边缘的属性。在LTR的方向下,为右边缘,在RTL的方向下,为左边缘。 |
513| top  | T    | 否|否|顶部边缘的属性。 |
514| bottom | T    | 否|否|底部边缘的属性。 |
515
516> **说明:**
517>
518>- 自定义布局暂不支持LazyForEach写法。
519>- 使用builder形式的自定义布局创建,自定义组件的build()方法内只允许存在this.builder(),即示例的推荐用法。
520>- 父容器(自定义组件)上设置的尺寸信息,除aspectRatio之外,优先级小于onMeasureSize设置的尺寸信息。
521>- 子组件设置的位置信息,offset、position、markAnchor优先级大于onPlaceChildren设置的位置信息,其他位置设置属性不生效。
522>- 使用自定义布局方法时,需要同时调用onMeasureSize和onPlaceChildren方法,否则可能出现布局异常。
523
524## onLayout<sup>(deprecated)</sup>
525
526onLayout?(children: Array&lt;LayoutChild&gt;, constraint: ConstraintSizeOptions): void
527
528ArkUI框架会在自定义组件布局时,将该自定义组件的子节点信息和自身的尺寸范围通过onLayout传递给该自定义组件。不允许在onLayout函数中改变状态变量。
529
530该接口从API version 9开始支持,从API version 10开始废弃,推荐使用[onPlaceChildren](#onplacechildren10)替代。
531
532**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。
533
534**系统能力:** SystemCapability.ArkUI.ArkUI.Full
535
536**参数:**
537
538| 参数名        | 类型                                                         | 必填|说明               |
539|------------|------------------------------------------------------------|------|------------------|
540| children   | Array&lt;[LayoutChild](#layoutchilddeprecated)&gt;                | 是  | 子组件布局信息。         |
541| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 是  |父组件constraint信息。 |
542
543## onMeasure<sup>(deprecated)</sup>
544
545onMeasure?(children: Array&lt;LayoutChild&gt;, constraint: ConstraintSizeOptions): void
546
547ArkUI框架会在自定义组件确定尺寸时,将该自定义组件的子节点信息和自身的尺寸范围通过onMeasure传递给该自定义组件。不允许在onMeasure函数中改变状态变量。
548
549该接口从API version 9开始支持,从API version 10开始废弃,推荐使用[onMeasureSize](#onmeasuresize10)替代。
550
551**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。
552
553**系统能力:** SystemCapability.ArkUI.ArkUI.Full
554
555**参数:**
556
557| 参数名        | 类型                                                         |必填| 说明               |
558|------------|------------------------------------------------------------|------|------------------|
559| children   | Array&lt;[LayoutChild](#layoutchilddeprecated)&gt;                  | 是  |子组件布局信息。         |
560| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 是  |父组件constraint信息。 |
561
562## LayoutChild<sup>(deprecated)</sup>
563
564子组件布局信息。
565
566从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。
567
568**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。
569
570**系统能力:** SystemCapability.ArkUI.ArkUI.Full
571
572| 名称       | 类型                                                     | 只读|可选|说明                                   |
573| ---------- | ------------------------------------------------------------ | ------|------|-------------------------------------- |
574| name       | string                                                       | 否|否|子组件名称。                           |
575| id         | string                                                       | 否|否|子组件id。                             |
576| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)   | 否|否|子组件约束尺寸。                       |
577| borderInfo | [LayoutBorderInfo](#layoutborderinfodeprecated)              | 否|否|子组件border信息。                     |
578| position   | [Position](ts-types.md#position)                             | 否|否|子组件位置坐标。                       |
579| measure    | (childConstraint: [ConstraintSizeOptions](ts-types.md#constraintsizeoptions))&nbsp;=&gt;&nbsp;void |否|否| 调用此方法对子组件的尺寸范围进行限制。 |
580| layout     | (LayoutInfo: [LayoutInfo](#layoutinfodeprecated))&nbsp;=&gt;&nbsp;void | 否|否|调用此方法对子组件的位置信息进行限制。 |
581
582## LayoutBorderInfo<sup>(deprecated)</sup>
583
584子组件border信息。
585
586从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。
587
588**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。
589
590**系统能力:** SystemCapability.ArkUI.ArkUI.Full
591
592| 名称          | 类型                                 | 只读|可选|描述                      |
593|-------------|--------------------------------------|------|------|-------------------------|
594| borderWidth | [EdgeWidths](ts-types.md#edgewidths9) | 否|否|边框宽度类型,用于描述组件边框不同方向的宽度。 |
595| margin      | [Margin](ts-types.md#margin)         | 否|否|外边距类型,用于描述组件不同方向的外边距。   |
596| padding     | [Padding](ts-types.md#padding)       | 否|否|内边距类型,用于描述组件不同方向的内边距。   |
597
598## LayoutInfo<sup>(deprecated)</sup>
599
600子组件layout信息。
601
602从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。
603
604**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。
605
606**系统能力:** SystemCapability.ArkUI.ArkUI.Full
607
608| 名称       | 类型                                                   | 只读|可选|说明             |
609| ---------- | ---------------------------------------------------------- | ------|------|---------------- |
610| position   | [Position](ts-types.md#position)                           |否|否| 子组件位置坐标。 |
611| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 否|否|子组件约束尺寸。 |
612
613通过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![zh-cn_image_0000001511900496](figures/zh-cn_image_0000001511900496.png)