1# 自定义组件的自定义布局 2 3自定义组件的自定义布局用于通过数据计算的方式布局自定义组件内的子组件。 4 5> **说明:** 6> 7> 本模块首批接口从API version 9开始支持,后续版本的新增接口,采用上角标单独标记接口的起始版本。 8 9## onPlaceChildren<sup>10+</sup> 10 11onPlaceChildren?(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions):void 12 13ArkUI框架会在自定义组件布局时,将该自定义组件的子节点自身的尺寸范围通过onPlaceChildren传递给该自定义组件。不允许在onPlaceChildren函数中改变状态变量。 14 15**系统能力:** SystemCapability.ArkUI.ArkUI.Full 16 17**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 18 19**参数:** 20 21| 参数名 | 类型 | 说明 | 22|----------------|------------------------------------------------------------|------------------| 23| selfLayoutInfo | [GeometryInfo](#geometryinfo10) | 父组件布局信息。 | 24| children | Array<[Layoutable](#layoutable10)> | 子组件布局信息。 | 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<Measurable>, constraint: ConstraintSizeOptions): SizeResult 34 35ArkUI框架会在自定义组件确定尺寸时,将该自定义组件的节点信息和尺寸范围通过onMeasureSize传递给该开发者。不允许在onMeasureSize函数中改变状态变量。 36 37**系统能力:** SystemCapability.ArkUI.ArkUI.Full 38 39**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 40 41**参数:** 42 43| 参数名 | 类型 | 说明 | 44| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | 45| selfLayoutInfo | [GeometryInfo](#geometryinfo10) | 父组件布局信息。 | 46| children | Array<[Measurable](#measurable10)> | 子组件布局信息。<br/>**说明:** <br/>如果没有设置子组件的布局信息,子组件会维持上一次的布局信息,当子组件从来没有设置过尺寸时,尺寸默认为0。 | 47| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 父组件constraint信息。 | 48 49**返回值:** 50 51| 类型 | 描述 | 52| --------------------------- | -------------- | 53| [SizeResult](#sizeresult10) | 组件尺寸信息。 | 54 55**示例一:** 56自定义布局代码示例。 57``` 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 121 122**示例二:** 123通过组件的位置灵活判断是否参与布局计算。 124``` 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 222 223## GeometryInfo<sup>10+</sup> 224 225父组件布局信息,继承自[SizeResult](#sizeresult10)。 226 227**系统能力:** SystemCapability.ArkUI.ArkUI.Full 228 229**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 230 231| 属性 | 类型 | 说明 | 232|-------------|-----------|---------------------| 233| borderWidth | [EdgeWidth](ts-types.md#edgewidths9) | 父组件边框宽度。<br>单位:vp | 234| margin | [Margin](ts-types.md#margin) | 父组件margin信息。 <br>单位:vp | 235| padding | [Padding](ts-types.md#padding) | 父组件padding信息。<br>单位:vp | 236| width | number | 测量后的宽。<br>单位:vp<br> **说明:** <br>若值为空时,则返回组件的百分比宽。 | 237| height | number | 测量后的高。<br>单位:vp<br> **说明:** <br>若值为空时,则返回组件的百分比高。 | 238 239 240## Layoutable<sup>10+</sup> 241 242子组件布局信息。 243 244**系统能力:** SystemCapability.ArkUI.ArkUI.Full 245 246### 属性 247 248| 属性 | 类型 | 必填 | 说明 | 249|--------------|---------------------------------- | -----------------------------------------------|---------------------| 250| measureResult| [MeasureResult](#measureresult10) | 是| 子组件测量后的尺寸信息,继承自[SizeResult](#sizeresult10)<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。<br>单位:vp | 251 252 253### layout 254 255layout(position: Position) 256 257调用此方法对子组件的位置信息进行限制。 258 259**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 260 261**系统能力:** SystemCapability.ArkUI.ArkUI.Full 262 263**参数:** 264 265| 参数名 | 类型 | 必填 |说明 | 266|-----------------|---------------------------------------------------------|---------------------|-------------| 267| position | [Position](ts-types.md#position) | 是 | 位置。 | 268 269### getMargin<sup>12+</sup> 270 271getMargin() : DirectionalEdgesT\<number> 272 273调用此方法获得子组件的margin信息。 274 275**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 276 277**返回值:** 278 279| 类型 | 说明 | 280|------------------------------------|---------------------------------------------| 281| [DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的margin信息。 | 282 283 ### getPadding<sup>12+</sup> 284 285getPadding() : DirectionalEdgesT\<number> 286 287 调用此方法获得子组件的padding信息。 288 289**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 290 291 **返回值:** 292 293| 类型 | 说明 | 294|------------------------------------|---------------------------------------------| 295| [DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的padding信息。 | 296 297### getBorderWidth<sup>12+</sup> 298 299getBorderWidth() : DirectionalEdgesT\<number> 300 301调用此方法获得子组件的borderWidth信息。 302 303**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 304 305**返回值:** 306 307| 类型 | 说明 | 308|------------------------------------|---------------------------------------------| 309| [DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的borderWidth信息。 | 310 311## Measurable<sup>10+</sup> 312 313子组件位置信息。 314 315**系统能力:** SystemCapability.ArkUI.ArkUI.Full 316 317**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 318 319### measure 320 321 measure(constraint: ConstraintSizeOptions) : MeasureResult 322 323 调用此方法对子组件的尺寸范围进行限制。 324 325 **系统能力:** SystemCapability.ArkUI.ArkUI.Full 326 327**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 328 329**参数:** 330 331| 参数名 | 类型 | 必填 |说明 | 332|-----------------|---------------------------------------------------------|---------------------|-------------| 333| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 是 | 约束尺寸。 | 334 335**返回值:** 336 337 | 类型 | 说明 | 338 |------------------------------------|-------------------------| 339 |[MeasureResult](#measureresult10) | 测量后的组件布局信息。 | 340 341 ### getMargin<sup>12+</sup> 342 343 getMargin() : DirectionalEdgesT\<number\> 344 345 获取子组件的margin信息。 346 347**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 348 349**系统能力:** SystemCapability.ArkUI.ArkUI.Full 350 351**返回值:** 352 353 | 类型 | 说明 | 354 |------------------------------------|-------------------------| 355 |[DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的margin信息。 | 356 357### getPadding<sup>12+</sup> 358 359getPadding() : DirectionalEdgesT\<number\> 360 361获取子组件的padding信息。 362 363**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 364 365**系统能力:** SystemCapability.ArkUI.ArkUI.Full 366 367**返回值:** 368 369 | 类型 | 说明 | 370 |------------------------------------|-------------------------| 371 |[DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的padding信息。 | 372 373 ### getBorderWidth<sup>12+</sup> 374 375getBorderWidth() : DirectionalEdgesT\<number\> 376 377获取子组件的borderWidth信息。 378 379**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 380 381**系统能力:** SystemCapability.ArkUI.ArkUI.Full 382 383**返回值:** 384 385 | 类型 | 说明 | 386 |------------------------------------|-------------------------| 387 |[DirectionalEdgesT<number>](#directionaledgestt12) | 子组件的borderWidth信息。| 388 389 390## MeasureResult<sup>10+</sup> 391 392测量后的组件布局信息。 393 394**系统能力:** SystemCapability.ArkUI.ArkUI.Full 395 396**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 397 398| 属性 | 类型 | 说明 | 399|--------|--------|-------| 400| width | number | 测量后的宽。<br>单位:vp | 401| height | number | 测量后的高。<br>单位:vp | 402 403 404## SizeResult<sup>10+</sup> 405 406组件尺寸信息。 407 408**系统能力:** SystemCapability.ArkUI.ArkUI.Full 409 410**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 411 412| 属性 | 类型 | 说明 | 413|--------|--------|-------| 414| width | number | 测量后的宽。<br>单位:vp | 415| height | number | 测量后的高。<br>单位:vp | 416 417## DirectionalEdgesT\<T><sup>12+</sup> 418 419全球化的边缘属性。 420 421**系统能力:** SystemCapability.ArkUI.ArkUI.Full 422 423**卡片能力:** 从API version 12开始,该接口支持在ArkTS卡片中使用。 424 425| 属性 | 类型 | 说明 | 426| ------ | ---- | ---------------- | 427| start | T | 起始边缘的属性。在LTR的方向下,为左边缘,在RTL的方向下,为右边缘。 | 428| end | T | 终止边缘的属性。在LTR的方向下,为右边缘,在RTL的方向下,为左边缘。 | 429| top | T | 顶部边缘的属性。 | 430| bottom | T | 底部边缘的属性。 | 431 432> **说明:** 433> 434>- 自定义布局暂不支持LazyForEach写法。 435>- 使用builder形式的自定义布局创建,自定义组件的build()方法内只允许存在this.builder(),即示例的推荐用法。 436>- 父容器(自定义组件)上设置的尺寸信息,除aspectRatio之外,优先级小于onMeasureSize设置的尺寸信息。 437>- 子组件设置的位置信息,offset、position、markAnchor优先级大于onPlaceChildren设置的位置信息,其他位置设置属性不生效。 438>- 使用自定义布局方法时,需要同时调用onMeasureSize和onPlaceChildren方法,否则可能出现布局异常。 439 440## onLayout<sup>(deprecated)</sup> 441 442onLayout?(children: Array<LayoutChild>, constraint: ConstraintSizeOptions): void 443 444ArkUI框架会在自定义组件布局时,将该自定义组件的子节点信息和自身的尺寸范围通过onLayout传递给该自定义组件。不允许在onLayout函数中改变状态变量。 445 446该接口从API version 9开始支持,从API version 10开始废弃,推荐使用[onPlaceChildren](#onplacechildren10)替代。 447 448**参数:** 449 450| 参数名 | 类型 | 说明 | 451|------------|------------------------------------------------------------|------------------| 452| children | Array<[LayoutChild](#layoutchilddeprecated)> | 子组件布局信息。 | 453| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 父组件constraint信息。 | 454 455## onMeasure<sup>(deprecated)</sup> 456 457onMeasure?(children: Array<LayoutChild>, constraint: ConstraintSizeOptions): void 458 459ArkUI框架会在自定义组件确定尺寸时,将该自定义组件的子节点信息和自身的尺寸范围通过onMeasure传递给该自定义组件。不允许在onMeasure函数中改变状态变量。 460 461该接口从API version 9开始支持,从API version 10开始废弃,推荐使用[onMeasureSize](#onmeasuresize10)替代。 462 463**参数:** 464 465| 参数名 | 类型 | 说明 | 466|------------|------------------------------------------------------------|------------------| 467| children | Array<[LayoutChild](#layoutchilddeprecated)> | 子组件布局信息。 | 468| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 父组件constraint信息。 | 469 470## LayoutChild<sup>(deprecated)</sup> 471 472子组件布局信息。 473 474从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。 475 476 477| 属性 | 类型 | 说明 | 478| ---------- | ------------------------------------------------------------ | -------------------------------------- | 479| name | string | 子组件名称。 | 480| id | string | 子组件id。 | 481| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 子组件约束尺寸。 | 482| borderInfo | [LayoutBorderInfo](#layoutborderinfodeprecated) | 子组件border信息。 | 483| position | [Position](ts-types.md#position) | 子组件位置坐标。 | 484| measure | (childConstraint: [ConstraintSizeOptions](ts-types.md#constraintsizeoptions)) => void | 调用此方法对子组件的尺寸范围进行限制。 | 485| layout | (LayoutInfo: [LayoutInfo](#layoutinfodeprecated)) => void | 调用此方法对子组件的位置信息进行限制。 | 486 487## LayoutBorderInfo<sup>(deprecated)</sup> 488 489子组件border信息。 490 491从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。 492 493| 属性 | 类型 | 描述 | 494|-------------|--------------------------------------|-------------------------| 495| borderWidth | [EdgeWidths](ts-types.md#edgewidths9) | 边框宽度类型,用于描述组件边框不同方向的宽度。 | 496| margin | [Margin](ts-types.md#margin) | 外边距类型,用于描述组件不同方向的外边距。 | 497| padding | [Padding](ts-types.md#padding) | 内边距类型,用于描述组件不同方向的内边距。 | 498 499## LayoutInfo<sup>(deprecated)</sup> 500 501子组件layout信息。 502 503从API version 9开始,从API version 10开始废弃,该接口支持在ArkTS卡片中使用。 504 505| 属性 | 类型 | 说明 | 506| ---------- | ---------------------------------------------------------- | ---------------- | 507| position | [Position](ts-types.md#position) | 子组件位置坐标。 | 508| constraint | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 子组件约束尺寸。 | 509 510通过layout修改布局。 511```ts 512// xxx.ets 513@Entry 514@Component 515struct Index { 516 build() { 517 Column() { 518 CustomLayout() { 519 ForEach([1, 2, 3], (index: number) => { 520 Text('Sub' + index) 521 .fontSize(30) 522 .borderWidth(2) 523 }) 524 } 525 } 526 } 527} 528 529 530@Component 531struct CustomLayout { 532 @Builder 533 doNothingBuilder() { 534 }; 535 536 @BuilderParam builder: () => void = this.doNothingBuilder; 537 538 onLayout(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) { 539 let pos = 0; 540 children.forEach((child) => { 541 child.layout({ position: { x: pos, y: pos }, constraint: constraint }) 542 pos += 70; 543 }) 544 } 545 546 onMeasure(children: Array<LayoutChild>, constraint: ConstraintSizeOptions) { 547 let size = 100; 548 children.forEach((child) => { 549 child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }) 550 size += 50; 551 }) 552 } 553 554 build() { 555 this.builder() 556 } 557} 558``` 559 560