彈性布局(Flex)

2024-01-25 13:10 更新

概述

彈性布局(Flex)提供更加有效的方式對(duì)容器中的子元素進(jìn)行排列、對(duì)齊和分配剩余空間。容器默認(rèn)存在主軸與交叉軸,子元素默認(rèn)沿主軸排列,子元素在主軸方向的尺寸稱為主軸尺寸,在交叉軸方向的尺寸稱為交叉軸尺寸。彈性布局在開發(fā)場(chǎng)景中用例特別多,比如頁(yè)面頭部導(dǎo)航欄的均勻分布、頁(yè)面框架的搭建、多行數(shù)據(jù)的排列等等。

圖1 主軸為水平方向的Flex容器示意圖

基本概念

  • 主軸:Flex組件布局方向的軸線,子元素默認(rèn)沿著主軸排列。主軸開始的位置稱為主軸起始點(diǎn),結(jié)束位置稱為主軸結(jié)束點(diǎn)。
  • 交叉軸:垂直于主軸方向的軸線。交叉軸開始的位置稱為交叉軸起始點(diǎn),結(jié)束位置稱為交叉軸結(jié)束點(diǎn)。

布局方向

在彈性布局中,容器的子元素可以按照任意方向排列。通過設(shè)置參數(shù)direction,可以決定主軸的方向,從而控制子組件的排列方向。

圖2 彈性布局方向圖
  • FlexDirection.Row(默認(rèn)值):主軸為水平方向,子組件從起始端沿著水平方向開始排布。

    1. Flex({ direction: FlexDirection.Row }) {
    2. Text('1').width('33%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .height(70)
    7. .width('90%')
    8. .padding(10)
    9. .backgroundColor(0xAFEEEE)

  • FlexDirection.RowReverse:主軸為水平方向,子組件從終點(diǎn)端沿著FlexDirection. Row相反的方向開始排布。

    1. Flex({ direction: FlexDirection.RowReverse }) {
    2. Text('1').width('33%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .height(70)
    7. .width('90%')
    8. .padding(10)
    9. .backgroundColor(0xAFEEEE)

  • FlexDirection.Column:主軸為垂直方向,子組件從起始端沿著垂直方向開始排布。

    1. Flex({ direction: FlexDirection.Column }) {
    2. Text('1').width('100%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('100%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('100%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .height(70)
    7. .width('90%')
    8. .padding(10)
    9. .backgroundColor(0xAFEEEE)

  • FlexDirection.ColumnReverse:主軸為垂直方向,子組件從終點(diǎn)端沿著FlexDirection. Column相反的方向開始排布。

    1. Flex({ direction: FlexDirection.ColumnReverse }) {
    2. Text('1').width('100%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('100%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('100%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .height(70)
    7. .width('90%')
    8. .padding(10)
    9. .backgroundColor(0xAFEEEE)

布局換行

彈性布局分為單行布局和多行布局。默認(rèn)情況下,F(xiàn)lex容器中的子元素都排在一條線(又稱“軸線”)上。wrap屬性控制當(dāng)子元素主軸尺寸之和大于容器主軸尺寸時(shí),F(xiàn)lex是單行布局還是多行布局。在多行布局時(shí),通過交叉軸方向,確認(rèn)新行堆疊方向。

  • FlexWrap. NoWrap(默認(rèn)值):不換行。如果子組件的寬度總和大于父元素的寬度,則子組件會(huì)被壓縮寬度。

    1. Flex({ wrap: FlexWrap.NoWrap }) {
    2. Text('1').width('50%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('50%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('50%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • FlexWrap. Wrap:換行,每一行子組件按照主軸方向排列。

    1. Flex({ wrap: FlexWrap.Wrap }) {
    2. Text('1').width('50%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('50%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('50%').height(50).backgroundColor(0xD2B48C)
    5. }
    6. .width('90%')
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • FlexWrap. WrapReverse:換行,每一行子組件按照主軸反方向排列。

    1. Flex({ wrap: FlexWrap.WrapReverse}) {
    2. Text('1').width('50%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('50%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('50%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

主軸對(duì)齊方式

通過justifyContent參數(shù)設(shè)置在主軸方向的對(duì)齊方式。

  • FlexAlign.Start(默認(rèn)值):子組件在主軸方向起始端對(duì)齊, 第一個(gè)子組件與父元素邊沿對(duì)齊,其他元素與前一個(gè)元素對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.Start }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

  • FlexAlign.Center:子組件在主軸方向居中對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.Center }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

  • FlexAlign.End:子組件在主軸方向終點(diǎn)端對(duì)齊, 最后一個(gè)子組件與父元素邊沿對(duì)齊,其他元素與后一個(gè)元素對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.End }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceBetween:Flex主軸方向均勻分配彈性元素,相鄰子組件之間距離相同。第一個(gè)子組件和最后一個(gè)子組件與父元素邊沿對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceAround:Flex主軸方向均勻分配彈性元素,相鄰子組件之間距離相同。第一個(gè)子組件到主軸起始端的距離和最后一個(gè)子組件到主軸終點(diǎn)端的距離是相鄰元素之間距離的一半。

    1. Flex({ justifyContent: FlexAlign.SpaceAround }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceEvenly:Flex主軸方向元素等間距布局,相鄰子組件之間的間距、第一個(gè)子組件與主軸起始端的間距、最后一個(gè)子組件到主軸終點(diǎn)端的間距均相等。

    1. Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
    2. Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
    3. Text('2').width('20%').height(50).backgroundColor(0xD2B48C)
    4. Text('3').width('20%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .width('90%')
    7. .padding({ top: 10, bottom: 10 })
    8. .backgroundColor(0xAFEEEE)

交叉軸對(duì)齊方式

容器和子元素都可以設(shè)置交叉軸對(duì)齊方式,且子元素設(shè)置的對(duì)齊方式優(yōu)先級(jí)較高。

容器組件設(shè)置交叉軸對(duì)齊

可以通過Flex組件的alignItems參數(shù)設(shè)置子組件在交叉軸的對(duì)齊方式。

  • ItemAlign.Auto:使用Flex容器中默認(rèn)配置。

    1. Flex({ alignItems: ItemAlign.Auto }) {
    2. Text('1').width('33%').height(30).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(40).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • ItemAlign.Start:交叉軸方向首部對(duì)齊。

    1. Flex({ alignItems: ItemAlign.Start }) {
    2. Text('1').width('33%').height(30).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(40).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • ItemAlign.Center:交叉軸方向居中對(duì)齊。

    1. Flex({ alignItems: ItemAlign.Center }) {
    2. Text('1').width('33%').height(30).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(40).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • ItemAlign.End:交叉軸方向底部對(duì)齊。

    1. Flex({ alignItems: ItemAlign.End }) {
    2. Text('1').width('33%').height(30).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(40).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • ItemAlign.Stretch:交叉軸方向拉伸填充,在未設(shè)置尺寸時(shí),拉伸到容器尺寸。

    1. Flex({ alignItems: ItemAlign.Stretch }) {
    2. Text('1').width('33%').backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').backgroundColor(0xD2B48C)
    4. Text('3').width('33%').backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

  • ItemAlign. Baseline:交叉軸方向文本基線對(duì)齊。

    1. Flex({ alignItems: ItemAlign.Baseline }) {
    2. Text('1').width('33%').height(30).backgroundColor(0xF5DEB3)
    3. Text('2').width('33%').height(40).backgroundColor(0xD2B48C)
    4. Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
    5. }
    6. .size({ width: '90%', height: 80 })
    7. .padding(10)
    8. .backgroundColor(0xAFEEEE)

子組件設(shè)置交叉軸對(duì)齊

子組件的alignSelf屬性也可以設(shè)置子組件在父容器交叉軸的對(duì)齊格式,且會(huì)覆蓋Flex布局容器中alignItems配置。如下例所示:

  1. Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { // 容器組件設(shè)置子組件居中
  2. Text('alignSelf Start').width('25%').height(80)
  3. .alignSelf(ItemAlign.Start)
  4. .backgroundColor(0xF5DEB3)
  5. Text('alignSelf Baseline')
  6. .alignSelf(ItemAlign.Baseline)
  7. .width('25%')
  8. .height(80)
  9. .backgroundColor(0xD2B48C)
  10. Text('alignSelf Baseline').width('25%').height(100)
  11. .backgroundColor(0xF5DEB3)
  12. .alignSelf(ItemAlign.Baseline)
  13. Text('no alignSelf').width('25%').height(100)
  14. .backgroundColor(0xD2B48C)
  15. Text('no alignSelf').width('25%').height(100)
  16. .backgroundColor(0xF5DEB3)
  17. }.width('90%').height(220).backgroundColor(0xAFEEEE)

上例中,F(xiàn)lex容器中alignItems設(shè)置交叉軸子組件的對(duì)齊方式為居中,子組件自身設(shè)置了alignSelf屬性的情況,覆蓋父組件的alignItems值,表現(xiàn)為alignSelf的定義。

內(nèi)容對(duì)齊

可以通過alignContent參數(shù)設(shè)置子組件各行在交叉軸剩余空間內(nèi)的對(duì)齊方式,只在多行的flex布局中生效,可選值有:

  • FlexAlign.Start:子組件各行與交叉軸起點(diǎn)對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.Start }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

  • FlexAlign.Center:子組件各行在交叉軸方向居中對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.Center }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

  • FlexAlign.End:子組件各行與交叉軸終點(diǎn)對(duì)齊。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.End }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceBetween:子組件各行與交叉軸兩端對(duì)齊,各行間垂直間距平均分布。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.SpaceBetween }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceAround:子組件各行間距相等,是元素首尾行與交叉軸兩端距離的兩倍。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.SpaceAround }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

  • FlexAlign.SpaceEvenly: 子組件各行間距,子組件首尾行與交叉軸兩端距離都相等。

    1. Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.SpaceEvenly }) {
    2. Text('1').width('30%').height(20).backgroundColor(0xF5DEB3)
    3. Text('2').width('60%').height(20).backgroundColor(0xD2B48C)
    4. Text('3').width('40%').height(20).backgroundColor(0xD2B48C)
    5. Text('4').width('30%').height(20).backgroundColor(0xF5DEB3)
    6. Text('5').width('20%').height(20).backgroundColor(0xD2B48C)
    7. }
    8. .width('90%')
    9. .height(100)
    10. .backgroundColor(0xAFEEEE)

自適應(yīng)拉伸

在彈性布局父組件尺寸不夠大的時(shí)候,通過子組件的下面幾個(gè)屬性設(shè)置其在父容器的占比,達(dá)到自適應(yīng)布局能力。

  • flexBasis:設(shè)置子組件在父容器主軸方向上的基準(zhǔn)尺寸。如果設(shè)置了該值,則子項(xiàng)占用的空間為設(shè)置的值;如果沒設(shè)置該屬性,那子項(xiàng)的空間為width/height的值。

    1. Flex() {
    2. Text('flexBasis("auto")')
    3. .flexBasis('auto') // 未設(shè)置width以及flexBasis值為auto,內(nèi)容自身寬度
    4. .height(100)
    5. .backgroundColor(0xF5DEB3)
    6. Text('flexBasis("auto")' + ' width("40%")')
    7. .width('40%')
    8. .flexBasis('auto') //設(shè)置width以及flexBasis值auto,使用width的值
    9. .height(100)
    10. .backgroundColor(0xD2B48C)
    11. Text('flexBasis(100)') // 未設(shè)置width以及flexBasis值為100,寬度為100vp
    12. .fontSize(15)
    13. .flexBasis(100)
    14. .height(100)
    15. .backgroundColor(0xF5DEB3)
    16. Text('flexBasis(100)')
    17. .fontSize(15)
    18. .flexBasis(100)
    19. .width(200) // flexBasis值為100,覆蓋width的設(shè)置值,寬度為100vp
    20. .height(100)
    21. .backgroundColor(0xD2B48C)
    22. }.width('90%').height(120).padding(10).backgroundColor(0xAFEEEE)

  • flexGrow:設(shè)置父容器的剩余空間分配給此屬性所在組件的比例。用于“瓜分”父組件的剩余空間。
    1. Flex() {
    2. Text('flexGrow(2)')
    3. .flexGrow(2)
    4. .width(100)
    5. .height(100)
    6. .backgroundColor(0xF5DEB3)
    7. Text('flexGrow(3)')
    8. .flexGrow(3)
    9. .width(100)
    10. .height(100)
    11. .backgroundColor(0xD2B48C)
    12. Text('no flexGrow')
    13. .width(100)
    14. .height(100)
    15. .backgroundColor(0xF5DEB3)
    16. }.width(420).height(120).padding(10).backgroundColor(0xAFEEEE)

    父容器寬度420vp,三個(gè)子元素原始寬度為100vp,左右padding為20vp,總和320vp,剩余空間100vp根據(jù)flexGrow值的占比分配給子元素,未設(shè)置flexGrow的子元素不參與“瓜分”。

    第一個(gè)元素以及第二個(gè)元素以2:3分配剩下的100vp。第一個(gè)元素為100vp+100vp*2/5=140vp,第二個(gè)元素為100vp+100vp*3/5=160vp。

  • flexShrink: 當(dāng)父容器空間不足時(shí),子組件的壓縮比例。

    1. Flex({ direction: FlexDirection.Row }) {
    2. Text('flexShrink(3)')
    3. .fontSize(15)
    4. .flexShrink(3)
    5. .width(200)
    6. .height(100)
    7. .backgroundColor(0xF5DEB3)
    8. Text('no flexShrink')
    9. .width(200)
    10. .height(100)
    11. .backgroundColor(0xD2B48C)
    12. Text('flexShrink(2)')
    13. .flexShrink(2)
    14. .width(200)
    15. .height(100)
    16. .backgroundColor(0xF5DEB3)
    17. }.width(400).height(120).padding(10).backgroundColor(0xAFEEEE)

相關(guān)實(shí)例

使用彈性布局,可以實(shí)現(xiàn)子組件沿水平方向排列,兩端對(duì)齊,子組件間距平分,豎直方向上子組件居中的效果。

  1. @Entry
  2. @Component
  3. struct FlexExample {
  4. build() {
  5. Column() {
  6. Column({ space: 5 }) {
  7. Flex({ direction: FlexDirection.Row, wrap: FlexWrap.NoWrap, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
  8. Text('1').width('30%').height(50).backgroundColor(0xF5DEB3)
  9. Text('2').width('30%').height(50).backgroundColor(0xD2B48C)
  10. Text('3').width('30%').height(50).backgroundColor(0xF5DEB3)
  11. }
  12. .height(70)
  13. .width('90%')
  14. .backgroundColor(0xAFEEEE)
  15. }.width('100%').margin({ top: 5 })
  16. }.width('100%')
  17. }
  18. }

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)