1# 自定义组件的自定义布局
2
3如果需要通过测算的方式布局自定义组件内子组件的位置,建议使用以下接口:
4
5- [onMeasureSize](../reference/apis-arkui/arkui-ts/ts-custom-component-layout.md#onmeasuresize10):组件每次布局时触发,计算子组件的尺寸,其执行时间先于onPlaceChildren。
6
7- [onPlaceChildren](../reference/apis-arkui/arkui-ts/ts-custom-component-layout.md#onplacechildren10):组件每次布局时触发,设置子组件的起始位置。
8
9**示例:**
10
11```
12// xxx.ets
13@Entry
14@Component
15struct Index {
16  build() {
17    Column() {
18      CustomLayout({ builder: ColumnChildren })
19    }
20  }
21}
22
23// 通过builder的方式传递多个组件,作为自定义组件的一级子组件(即不包含容器组件,如Column)
24@Builder
25function ColumnChildren() {
26  ForEach([1, 2, 3], (index: number) => { // 暂不支持lazyForEach的写法
27    Text('S' + index)
28      .fontSize(30)
29      .width(100)
30      .height(100)
31      .borderWidth(2)
32      .offset({ x: 10, y: 20 })
33  })
34}
35
36@Component
37struct CustomLayout {
38  @Builder
39  doNothingBuilder() {
40  };
41
42  @BuilderParam builder: () => void = this.doNothingBuilder;
43  @State startSize: number = 100;
44  result: SizeResult = {
45    width: 0,
46    height: 0
47  };
48
49  // 第一步:计算各子组件的大小
50  onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) {
51    let size = 100;
52    children.forEach((child) => {
53      let result: MeasureResult = child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size })
54      size += result.width / 2;
55    })
56    this.result.width = 100;
57    this.result.height = 400;
58    return this.result;
59  }
60  // 第二步:放置各子组件的位置
61  onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) {
62    let startPos = 300;
63    children.forEach((child) => {
64      let pos = startPos - child.measureResult.height;
65      child.layout({ x: pos, y: pos })
66    })
67  }
68
69  build() {
70    this.builder()
71  }
72}
73```
74
75![custom-component-custom-layout](figures/custom-component-custom-layout.png)
76
77以上示例中,Index页面包含一个实现了自定义布局的自定义组件,且对应自定义组件的子组件通过index页面内的builder方式传入。
78
79而在自定义组件中,调用了onMeasureSize和onPlaceChildren设置子组件大小和放置位置。例如,在本示例中,在onMeasureSize中初始化组件大小size=100,后续的每一个子组件size会加上上一个子组件大小的一半,实现组件大小递增的效果。而在onPlaceChildren中,定义startPos=300,设置每一个子组件的位置为startPos减去子组件自身的高度,所有子组件右下角一致在顶点位置(300,300),实现一个从右下角开始展示组件的类Stack组件。