1# Flex 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @camlostshi--> 5<!--Designer: @lanshouren--> 6<!--Tester: @liuli0427--> 7<!--Adviser: @HelloCrease--> 8 9Flex是以弹性方式布局子组件的容器组件,能够高效地排列、对齐子元素并分配剩余空间。 10 11具体指南请参考[弹性布局](../../../ui/arkts-layout-development-flex-layout.md)。 12 13> **说明:** 14> 15> - 该组件从API version 7开始支持。后续版本如有新增内容将采用上角标单独标记该内容的起始版本。 16> - Flex组件在渲染时存在二次布局过程,因此在对性能有严格要求的场景下建议使用[Column](ts-container-column.md)、[Row](ts-container-row.md)代替。最佳实践请参考[合理使用布局-合理使用布局组件](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-improve-layout-performance#section12745188175420)。 17> - Flex组件主轴不设置长度时默认撑满父容器,[Column](ts-container-column.md)、[Row](ts-container-row.md)组件主轴不设置长度时默认跟随子节点大小。 18> - Flex、Column、Row组件在没有子节点且不设置宽高时,默认宽高为-1。 19> - 主轴长度可设置为auto使Flex自适应子组件布局,自适应时,Flex长度受constraintSize属性以及父容器传递的最大最小长度限制,且constraintSize属性优先级更高。 20 21 22## 子组件 23 24可以包含子组件。 25 26## 接口 27 28Flex(value?: FlexOptions) 29 30Flex布局容器。 31 32**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 33 34**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 35 36**系统能力:** SystemCapability.ArkUI.ArkUI.Full 37 38**参数:** 39 40| 参数名 | 类型 | 必填 | 说明 | 41| -------------- | ---------------------------------------- | ---- | ---------------------------------------- | 42| value | [FlexOptions](#flexoptions对象说明) | 否 | 弹性布局子组件参数。 | 43 44## FlexOptions对象说明 45 46设置Flex子组件的排列对齐方式。 47 48**系统能力:** SystemCapability.ArkUI.ArkUI.Full 49 50| 名称 | 类型 | 只读 | 可选 | 说明 | 51| -------- | -------- | -------- | -------- | -------- | 52| direction | [FlexDirection](ts-appendix-enums.md#flexdirection) | 否 | 是 | 子组件在Flex容器上排列的方向,即主轴的方向。<br/>**默认值:** FlexDirection.Row <br />**非法值:** 按默认值处理。<br/>**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 53| wrap | [FlexWrap](ts-appendix-enums.md#flexwrap) | 否 | 是 | Flex容器是单行/列还是多行/列排列。<br/>**默认值:** FlexWrap.NoWrap <br />**非法值:** 按默认值处理。<br/>**说明:** <br/>在多行布局时,通过交叉轴方向,确认新行堆叠方向。<br/>**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 54| justifyContent | [FlexAlign](ts-appendix-enums.md#flexalign) | 否 | 是 | 所有子组件在Flex容器主轴上的对齐格式。<br/>**默认值:** FlexAlign.Start <br />**非法值:** 按默认值处理。<br/>**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 55| alignItems | [ItemAlign](ts-appendix-enums.md#itemalign) | 否 | 是 | 所有子组件在Flex容器交叉轴上的对齐格式。 <br/>**默认值:** ItemAlign.Start <br />**非法值:** 按默认值处理。<br/>**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 <br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 56| alignContent | [FlexAlign](ts-appendix-enums.md#flexalign) | 否 | 是 | 交叉轴中有额外的空间时,多行内容的对齐方式。仅在wrap为Wrap或WrapReverse下生效。<br/>**默认值:** FlexAlign.Start <br />**非法值:** 按默认值处理。<br/>**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 57| space<sup>12+</sup> | [FlexSpaceOptions<sup>12+</sup>](ts-container-flex.md#flexspaceoptions12) | 否 | 是 | 所有子组件在Flex容器主轴或交叉轴的间距。<br/>**默认值:** {main: LengthMetrics.px(0), cross: LengthMetrics.px(0)} <br />**非法值:** 按默认值处理。 <br/>space为负数、百分比或者justifyContent设置为FlexAlign.SpaceBetween、FlexAlign.SpaceAround、FlexAlign.SpaceEvenly时不生效。 <br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。| 58 59## FlexSpaceOptions<sup>12+</sup> 60 61设置Flex容器的子组件在主轴或交叉轴的间距。 62 63**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 64 65**系统能力:** SystemCapability.ArkUI.ArkUI.Full 66 67| 名称 | 类型 | 只读 | 可选 | 说明 | 68| ----------- | --------- | ----------- | --------- |----------- | 69| main | [LengthMetrics](../js-apis-arkui-graphics.md#lengthmetrics12) | 否 | 是 | Flex容器主轴上的space。<br/> **默认值:** LengthMetrics.px(0) | 70| cross | [LengthMetrics](../js-apis-arkui-graphics.md#lengthmetrics12) | 否 | 是 | Flex容器交叉轴上的space。<br/> **默认值:** LengthMetrics.px(0) | 71 72## 属性 73 74支持[通用属性](ts-component-general-attributes.md)。 75 76## 事件 77 78支持[通用事件](ts-component-general-events.md)。 79 80## 示例 81 82### 示例1(子组件排列方向) 83该示例通过设置direction实现不同的子组件排列方向效果。 84```ts 85// xxx.ets 86@Entry 87@Component 88struct FlexExample1 { 89 build() { 90 Column() { 91 Column({ space: 5 }) { 92 Text('direction:Row').fontSize(9).fontColor(0xCCCCCC).width('90%') 93 Flex({ direction: FlexDirection.Row }) { // 子组件在容器主轴上行布局 94 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 95 Text('2').width('20%').height(50).backgroundColor(0xD2B48C) 96 Text('3').width('20%').height(50).backgroundColor(0xF5DEB3) 97 Text('4').width('20%').height(50).backgroundColor(0xD2B48C) 98 } 99 .height(70) 100 .width('90%') 101 .padding(10) 102 .backgroundColor(0xAFEEEE) 103 104 Text('direction:RowReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 105 Flex({ direction: FlexDirection.RowReverse }) { // 子组件在容器主轴上反向行布局 106 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 107 Text('2').width('20%').height(50).backgroundColor(0xD2B48C) 108 Text('3').width('20%').height(50).backgroundColor(0xF5DEB3) 109 Text('4').width('20%').height(50).backgroundColor(0xD2B48C) 110 } 111 .height(70) 112 .width('90%') 113 .padding(10) 114 .backgroundColor(0xAFEEEE) 115 116 Text('direction:Column').fontSize(9).fontColor(0xCCCCCC).width('90%') 117 Flex({ direction: FlexDirection.Column }) { // 子组件在容器主轴上列布局 118 Text('1').width('100%').height(40).backgroundColor(0xF5DEB3) 119 Text('2').width('100%').height(40).backgroundColor(0xD2B48C) 120 Text('3').width('100%').height(40).backgroundColor(0xF5DEB3) 121 Text('4').width('100%').height(40).backgroundColor(0xD2B48C) 122 } 123 .height(160) 124 .width('90%') 125 .padding(10) 126 .backgroundColor(0xAFEEEE) 127 128 Text('direction:ColumnReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 129 Flex({ direction: FlexDirection.ColumnReverse }) { // 子组件在容器主轴上反向列布局 130 Text('1').width('100%').height(40).backgroundColor(0xF5DEB3) 131 Text('2').width('100%').height(40).backgroundColor(0xD2B48C) 132 Text('3').width('100%').height(40).backgroundColor(0xF5DEB3) 133 Text('4').width('100%').height(40).backgroundColor(0xD2B48C) 134 } 135 .height(160) 136 .width('90%') 137 .padding(10) 138 .backgroundColor(0xAFEEEE) 139 }.width('100%').margin({ top: 5 }) 140 }.width('100%') 141 } 142} 143``` 144 145 146 147### 示例2(子组件单/多行排列) 148该示例通过设置wrap实现子组件单行或多行的排列效果。 149```ts 150// xxx.ets 151@Entry 152@Component 153struct FlexExample2 { 154 build() { 155 Column() { 156 Column({ space: 5 }) { 157 Text('Wrap').fontSize(9).fontColor(0xCCCCCC).width('90%') 158 Flex({ wrap: FlexWrap.Wrap }) { // 子组件多行布局 159 Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) 160 Text('2').width('50%').height(50).backgroundColor(0xD2B48C) 161 Text('3').width('50%').height(50).backgroundColor(0xD2B48C) 162 } 163 .width('90%') 164 .padding(10) 165 .backgroundColor(0xAFEEEE) 166 167 Text('NoWrap').fontSize(9).fontColor(0xCCCCCC).width('90%') 168 Flex({ wrap: FlexWrap.NoWrap }) { // 子组件单行布局 169 Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) 170 Text('2').width('50%').height(50).backgroundColor(0xD2B48C) 171 Text('3').width('50%').height(50).backgroundColor(0xF5DEB3) 172 } 173 .width('90%') 174 .padding(10) 175 .backgroundColor(0xAFEEEE) 176 177 Text('WrapReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 178 Flex({ wrap: FlexWrap.WrapReverse , direction:FlexDirection.Row }) { // 子组件反向多行布局 179 Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) 180 Text('2').width('50%').height(50).backgroundColor(0xD2B48C) 181 Text('3').width('50%').height(50).backgroundColor(0xD2B48C) 182 } 183 .width('90%') 184 .height(120) 185 .padding(10) 186 .backgroundColor(0xAFEEEE) 187 }.width('100%').margin({ top: 5 }) 188 }.width('100%') 189 } 190} 191``` 192 193 194 195### 示例3(子组件在主轴上的对齐格式) 196该示例通过设置justifyContent实现子组件在主轴上不同的对齐效果。 197```ts 198// xxx.ets 199@Component 200struct JustifyContentFlex { 201 justifyContent : number = 0; 202 203 build() { 204 Flex({ justifyContent: this.justifyContent }) { 205 Text('1').width('20%').height(50).backgroundColor(0xF5DEB3) 206 Text('2').width('20%').height(50).backgroundColor(0xD2B48C) 207 Text('3').width('20%').height(50).backgroundColor(0xF5DEB3) 208 } 209 .width('90%') 210 .padding(10) 211 .backgroundColor(0xAFEEEE) 212 } 213} 214 215@Entry 216@Component 217struct FlexExample3 { 218 build() { 219 Column() { 220 Column({ space: 5 }) { 221 Text('justifyContent:Start').fontSize(9).fontColor(0xCCCCCC).width('90%') 222 JustifyContentFlex({ justifyContent: FlexAlign.Start }) // 子组件在容器主轴上首端对齐 223 224 Text('justifyContent:Center').fontSize(9).fontColor(0xCCCCCC).width('90%') 225 JustifyContentFlex({ justifyContent: FlexAlign.Center }) // 子组件在容器主轴上居中对齐 226 227 Text('justifyContent:End').fontSize(9).fontColor(0xCCCCCC).width('90%') 228 JustifyContentFlex({ justifyContent: FlexAlign.End }) // 子组件在容器主轴上尾端对齐 229 230 Text('justifyContent:SpaceBetween').fontSize(9).fontColor(0xCCCCCC).width('90%') 231 JustifyContentFlex({ justifyContent: FlexAlign.SpaceBetween }) // 子组件在容器主轴上均分容器布局,第一个子组件与行首对齐,最后一个子组件与行尾对齐。 232 233 Text('justifyContent:SpaceAround').fontSize(9).fontColor(0xCCCCCC).width('90%') 234 JustifyContentFlex({ justifyContent: FlexAlign.SpaceAround }) // 子组件在容器主轴上均分容器布局,第一个子组件到行首的距离和最后一个子组件到行尾的距离是相邻子组件之间距离的一半。 235 236 Text('justifyContent:SpaceEvenly').fontSize(9).fontColor(0xCCCCCC).width('90%') 237 JustifyContentFlex({ justifyContent: FlexAlign.SpaceEvenly }) // 子组件在容器主轴上均分容器布局,子组件之间的距离与第一子组件到行首、最后一个子组件到行尾的距离相等 238 }.width('100%').margin({ top: 5 }) 239 }.width('100%') 240 } 241} 242``` 243 244 245 246### 示例4(子组件在交叉轴上的对齐方式) 247该示例通过设置alignItems实现子组件在交叉轴上的不同的对齐效果。 248```ts 249// xxx.ets 250@Component 251struct AlignItemsFlex { 252 alignItems : number = 0; 253 254 build() { 255 Flex({ alignItems: this.alignItems }) { 256 Text('1').width('33%').height(30).backgroundColor(0xF5DEB3) 257 Text('2').width('33%').height(40).backgroundColor(0xD2B48C) 258 Text('3').width('33%').height(50).backgroundColor(0xF5DEB3) 259 } 260 .size({width: '90%', height: 80}) 261 .padding(10) 262 .backgroundColor(0xAFEEEE) 263 } 264} 265 266@Entry 267@Component 268struct FlexExample4 { 269 build() { 270 Column() { 271 Column({ space: 5 }) { 272 Text('alignItems:Auto').fontSize(9).fontColor(0xCCCCCC).width('90%') 273 AlignItemsFlex({ alignItems: ItemAlign.Auto }) // 子组件在容器交叉轴上首部对齐 274 275 Text('alignItems:Start').fontSize(9).fontColor(0xCCCCCC).width('90%') 276 AlignItemsFlex({ alignItems: ItemAlign.Start }) // 子组件在容器交叉轴上首部对齐 277 278 Text('alignItems:Center').fontSize(9).fontColor(0xCCCCCC).width('90%') 279 AlignItemsFlex({ alignItems: ItemAlign.Center }) // 子组件在容器交叉轴上居中对齐 280 281 Text('alignItems:End').fontSize(9).fontColor(0xCCCCCC).width('90%') 282 AlignItemsFlex({ alignItems: ItemAlign.End }) // 子组件在容器交叉轴上尾部对齐 283 284 Text('alignItems:Stretch').fontSize(9).fontColor(0xCCCCCC).width('90%') 285 AlignItemsFlex({ alignItems: ItemAlign.Stretch }) // 子组件在容器交叉轴上拉伸填充 286 287 Text('alignItems:Baseline').fontSize(9).fontColor(0xCCCCCC).width('90%') 288 AlignItemsFlex({ alignItems: ItemAlign.Baseline }) // 子组件在容器交叉轴上与文本基线对齐 289 }.width('100%').margin({ top: 5 }) 290 }.width('100%') 291 } 292} 293``` 294 295 296 297### 示例5(多行内容的对齐方式) 298该示例通过设置alignContent实现多行内容的不同对齐效果。 299```ts 300// xxx.ets 301@Component 302struct AlignContentFlex { 303 alignContent: number = 0; 304 305 build() { 306 Flex({ wrap: FlexWrap.Wrap, alignContent: this.alignContent }) { 307 Text('1').width('50%').height(20).backgroundColor(0xF5DEB3) 308 Text('2').width('50%').height(20).backgroundColor(0xD2B48C) 309 Text('3').width('50%').height(20).backgroundColor(0xD2B48C) 310 } 311 .size({ width: '90%', height: 90 }) 312 .padding(10) 313 .backgroundColor(0xAFEEEE) 314 } 315} 316 317@Entry 318@Component 319struct FlexExample5 { 320 build() { 321 Column() { 322 Column({ space: 5 }) { 323 Text('alignContent:Start').fontSize(9).fontColor(0xCCCCCC).width('90%') 324 AlignContentFlex({ alignContent: FlexAlign.Start }) // 多行布局下子组件首部对齐 325 326 Text('alignContent:Center').fontSize(9).fontColor(0xCCCCCC).width('90%') 327 AlignContentFlex({ alignContent: FlexAlign.Center }) // 多行布局下子组件居中对齐 328 329 Text('alignContent:End').fontSize(9).fontColor(0xCCCCCC).width('90%') 330 AlignContentFlex({ alignContent: FlexAlign.End }) // 多行布局下子组件尾部对齐 331 332 Text('alignContent:SpaceBetween').fontSize(9).fontColor(0xCCCCCC).width('90%') 333 AlignContentFlex({ alignContent: FlexAlign.SpaceBetween }) // 多行布局下第一行子组件与列首对齐,最后一行子组件与列尾对齐 334 335 Text('alignContent:SpaceAround').fontSize(9).fontColor(0xCCCCCC).width('90%') 336 AlignContentFlex({ alignContent: FlexAlign.SpaceAround }) // 多行布局下第一行子组件到列首的距离和最后一行子组件到列尾的距离是相邻行之间距离的一半 337 338 Text('alignContent:SpaceEvenly').fontSize(9).fontColor(0xCCCCCC).width('90%') 339 Flex({ 340 wrap: FlexWrap.Wrap, 341 alignContent: FlexAlign.SpaceEvenly 342 }) { // 多行布局下相邻行之间的距离与第一行子组件到列首的距离、最后一行子组件到列尾的距离完全一样 343 Text('1').width('50%').height(20).backgroundColor(0xF5DEB3) 344 Text('2').width('50%').height(20).backgroundColor(0xD2B48C) 345 Text('3').width('50%').height(20).backgroundColor(0xF5DEB3) 346 Text('4').width('50%').height(20).backgroundColor(0xD2B48C) 347 Text('5').width('50%').height(20).backgroundColor(0xF5DEB3) 348 } 349 .size({ width: '90%', height: 100 }) 350 .padding({ left: 10, right: 10 }) 351 .backgroundColor(0xAFEEEE) 352 }.width('100%').margin({ top: 5 }) 353 }.width('100%') 354 } 355} 356``` 357 358 359 360### 示例6(子组件单/多行排列时的主/交叉轴间距) 361该示例通过设置space为单/多行排列的子组件确定在主/交叉轴上的间距。 362```ts 363import {LengthMetrics} from '@kit.ArkUI'; 364 365@Entry 366@Component 367struct FlexExample2 { 368 build() { 369 Column() { 370 Column({ space: 5 }) { 371 Text('Wrap').fontSize(9).fontColor(0xCCCCCC).width('90%') 372 Flex({ wrap: FlexWrap.Wrap, space: {main: LengthMetrics.px(50), cross: LengthMetrics.px(50)} }) { // 子组件多行布局 373 Text('1').width('40%').height(50).backgroundColor(0xF5DEB3) 374 Text('2').width('40%').height(50).backgroundColor(0xD2B48C) 375 Text('3').width('40%').height(50).backgroundColor(0xD2B48C) 376 } 377 .width('90%') 378 .padding(10) 379 .backgroundColor(0xAFEEEE) 380 381 Text('NoWrap').fontSize(9).fontColor(0xCCCCCC).width('90%') 382 Flex({ wrap: FlexWrap.NoWrap, space: {main: LengthMetrics.px(50), cross: LengthMetrics.px(50)} }) { // 子组件单行布局 383 Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) 384 Text('2').width('50%').height(50).backgroundColor(0xD2B48C) 385 Text('3').width('50%').height(50).backgroundColor(0xF5DEB3) 386 } 387 .width('90%') 388 .padding(10) 389 .backgroundColor(0xAFEEEE) 390 391 Text('WrapReverse').fontSize(9).fontColor(0xCCCCCC).width('90%') 392 Flex({ wrap: FlexWrap.WrapReverse, direction:FlexDirection.Row, space: {main: LengthMetrics.px(50), cross: LengthMetrics.px(50)} }) { // 子组件反向多行布局 393 Text('1').width('40%').height(50).backgroundColor(0xF5DEB3) 394 Text('2').width('40%').height(50).backgroundColor(0xD2B48C) 395 Text('3').width('40%').height(50).backgroundColor(0xD2B48C) 396 } 397 .width('90%') 398 .height(120) 399 .padding(10) 400 .backgroundColor(0xAFEEEE) 401 }.width('100%').margin({ top: 5 }) 402 }.width('100%') 403 } 404} 405``` 406 407 408 409### 示例7(宽度自适应的Flex容器) 410该示例实现了Flex在宽度设置auto后可以自适应子组件布局的能力。 411```ts 412@Component 413struct Demo { 414 @Require @Prop text: string 415 416 build() { 417 Button() { 418 Flex() { 419 Image($r('sys.media.ohos_ic_public_voice')) 420 .width(16) 421 .height(16) 422 423 Row() { 424 Text(this.text) 425 .margin({ 426 left: 6, 427 right: 6 428 }) 429 .fontSize(14) 430 .maxLines(1) 431 .textOverflow({ overflow: TextOverflow.Ellipsis }) 432 } 433 434 Image($r('sys.media.ohos_ic_public_sound')) 435 .width(16) 436 .height(16) 437 }.width("auto") 438 } 439 .backgroundColor(0xAFEEEE) 440 .height(36) 441 .padding({ left: 16, right: 16 }) 442 .constraintSize({ maxWidth: 156 }) 443 .width("auto") 444 } 445} 446 447@Entry 448@Component 449struct Index { 450 build() { 451 Column({ space: 12 }) { 452 Text("Width does not reach max length").fontSize(11).fontColor(0XCCCCCC).width("50%") 453 Demo({ text: "123" }) 454 Text("Width reaches max length").fontSize(11).fontColor(0XCCCCCC).width("50%") 455 Demo({ text: "1234567890-1234567890-1234567890-1234567890" }) 456 } 457 } 458} 459``` 460 461 462