如何解决Flex组件设置width('auto')不生效的问题
===============================

#### 问题现象

Flex组件同时设置FlexWrap.Wrap和width('auto')后，宽度会占用一整行不会自动调整，该如何解决？

问题现象代码如下：

import { window } from '@kit.ArkUI';

@Entry
@Component
struct FlexPage {
  @State textList1: string\[\] \= \['文本XXX', '文本XXXXX', '文本XXXXXX', '文本XXXXXXX', '文本XX', '文本X'\];
  @State textList2: string\[\] \= \['文本XXX'\];

  aboutToAppear(): void {
    window.getLastWindow(this.getUIContext().getHostContext(), (err, data) \=\> {
      data?.setWindowLayoutFullScreen(true); _// 设置沉浸式布局_
    });
  }

  build() {
    Column() {
      Column({ space: 10 }) {
        Text(\`换行时想要的效果\`);
        Flex({ justifyContent: FlexAlign.Start, wrap: FlexWrap.Wrap, direction: FlexDirection.Row }) {
          ForEach(this.textList1, (item: string) \=\> {
            Text(item)
              .fontSize(12)
              .maxLines(1)
              .backgroundColor('#330A59F7')
              .borderRadius(4)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
              .ellipsisMode(EllipsisMode.END)
              .margin(3)
              .padding({ left: 12, right: 12 })
              .height(32);
          });
        }
        .padding(6)
        .backgroundColor('#ffffff')
        .width('auto')
        .margin({ bottom: 10 });

        Text(\`不换行时想要的效果\`);
        Flex({ justifyContent: FlexAlign.Start, direction: FlexDirection.Row }) {
          ForEach(this.textList2, (item: string) \=\> {
            Text(item)
              .fontSize(12)
              .maxLines(1)
              .backgroundColor('#330A59F7')
              .borderRadius(4)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
              .ellipsisMode(EllipsisMode.END)
              .margin(3)
              .padding({ left: 12, right: 12 })
              .height(32);
          });
        }
        .padding(6)
        .backgroundColor(Color.White)
        .width('auto')
        .margin({ bottom: 10 });

        Text(\`FlexWrap.Wrap换行和.width('auto')都设置时，width('auto')不生效\`);
        Flex({ justifyContent: FlexAlign.Start, wrap: FlexWrap.Wrap, direction: FlexDirection.Row }) {
          ForEach(this.textList2, (item: string) \=\> {
            Text(item)
              .fontSize(12)
              .maxLines(1)
              .backgroundColor('#330A59F7')
              .borderRadius(4)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
              .ellipsisMode(EllipsisMode.END)
              .margin(3)
              .padding({ left: 12, right: 12 })
              .height(32);
          });
        }
        .padding(6) _// Flex__内边距_
        .backgroundColor('#ffffff')
        .width('auto'); _// 宽度设置为自适应子组件宽度_
      }
      .width('100%')
      .alignItems(HorizontalAlign.Start);
    }
    .padding({
      top: 50,
      left: 20,
      right: 20,
      bottom: 50
    })
    .height('100%')
    .width('100%')
    .backgroundColor('#f1f3f5');
  }
}

问题效果图如下：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/4e/v3/r3gtPRYuQS2LmK8Qpe6fmw/zh-cn_image_0000002628561710.png?HW-CC-KV=V1&HW-CC-Date=20260709T133927Z&HW-CC-Expire=86400&HW-CC-Sign=4AF442A9C936FE5689034440456F901335334087ED8BF80F61B4545C54444223 "点击放大")

#### 背景知识

*   [Flex](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-flex)是以弹性方式布局子组件的容器组件，能够高效地排列、对齐子元素并分配剩余空间。
*   [FlexOptions](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-flex#flexoptions对象说明)对象用于设置子组件的排列对齐方式，主轴的方向[FlexDirection](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-appendix-enums#flexdirection)、换行方式[FlexWrap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-appendix-enums#flexwrap)。主轴长度可设置为auto使Flex自适应子组件布局。
*   [onSizeChange](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-component-size-change-event#onsizechange)是组件显示的尺寸发生变化时触发的事件回调，该事件返回的宽高是组件绘制出来的宽高。
*   [MeasureUtils](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-measureutils)提供文本宽度、高度等相关计算。使用[UIContext](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext)中的[getMeasureUtils](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext#getmeasureutils12)方法能够获取MeasureUtils实例。此实例中[measureText](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-measureutils#measuretext12)方法可以计算单行文本显示时的宽度。

#### 解决方案

当Flex组件参数wrap设置为FlexWrap.Wrap或FlexWrap.WrapReverse时，主轴长度auto的自适应布局会失效，默认撑满父容器。所以要解决问题可以控制Flex组件的换行规则：当内容不超过1行时设置为FlexWrap.NoWrap，超过1行设置为FlexWrap.Wrap。可采用如下两种方案。

*   方案一：
    
    默认组件当前为多行FlexWrap.Wrap，通过onSizeChange事件获取组件的高度。当组件高度大于1行时不做处理，小于1行时设置为FlexWrap.NoWrap，让width('auto')生效。
    
    import { window } from '@kit.ArkUI';
    
    @Entry
    @Component
    struct FlexPage1 {
      @State textList: string\[\] \= \['文本XXX', '文本XXXXX', '文本XXXXXX', '文本XXXXXXX', '文本XX', '文本X'\];
      @State isWarp: boolean \= true;
    
      aboutToAppear(): void {
        window.getLastWindow(this.getUIContext().getHostContext(), (err, data) \=\> {
          data.setWindowLayoutFullScreen(true); _// 设置沉浸式布局_
        });
      }
    
      build() {
        Column({ space: 10 }) {
          Column({ space: 10 }) {
            Text(\`根据初始行数决定是否关闭换行\`);
            Flex({
              justifyContent: FlexAlign.Start,
              wrap: this.isWarp ? FlexWrap.Wrap : FlexWrap.NoWrap, _// 根据状态变量设置是否换行_
              direction: FlexDirection.Row
            }) {
              ForEach(this.textList, (item: string) \=\> {
                Text(item)
                  .fontSize(12)
                  .maxLines(1)
                  .backgroundColor('#330A59F7')
                  .borderRadius(4)
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .ellipsisMode(EllipsisMode.END)
                  .margin(3) _// 文本框间距_
                  .padding({ left: 12, right: 12 })
                  .height(32); _//_ _文本框高度_
              });
            }
            .padding(6) _// Flex__内间距_
            .backgroundColor('#ffffff')
            .width('auto') _// Flex方向为Row时设置_
            .onSizeChange((oldValue, newValue) \=\> {
              _//_ _获取组件高度_
              let height \= newValue.height as number;
             _ // 组件高度是否不超过一行文本框时的高度（文本高度32+文本上下间距3\*2+Flex组件内间距6\*2）_
              if (height <\= (32 \+ 3 \* 2 \+ 6 \* 2)) {
                this.isWarp \= false; _// 文本不超过一行，不换行_
              }
            });
          }.width('100%')
          .alignItems(HorizontalAlign.Start);
    
          Button('更换数据1')
            .onClick(() \=\> {
              this.isWarp \= true; _//_ _默认换行_
              this.textList \= \['文本XXXX', '文本X'\]; _// 修改Flex中的内容触发改变宽高触发onSizeChange，判断是否取消换行_
            });
          Button('更新数据2')
            .onClick(() \=\> {
              this.isWarp \= true;
              this.textList \= \['文本XXXX', '文本X', '文本XXXXXXXXX', '文本XXXXXX', '文本XXX', '文本XX', '文本X', '文本XXX'\];
            });
        }
        .padding({
          top: 50,
          left: 20,
          right: 20,
          bottom: 20
        })
        .height('100%')
        .width('100%')
        .backgroundColor('#f1f3f5');
      }
    }
    
    运行效果图如下：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f0/v3/j2p4qqyOSOmb1D04cMIRtg/zh-cn_image_0000002658921029.png?HW-CC-KV=V1&HW-CC-Date=20260709T133927Z&HW-CC-Expire=86400&HW-CC-Sign=6773A83A20DF48F2CE144457D4E4FB5E70CCE8D1DDD25F11EE7CD66A4E75CAFE "点击放大")
    
*   方案二：
    
    首先根据设置的布局计算出Flex组件中一行可用的最大宽度。通过measureText得到文本占用的宽度，从而计算文本框占用的宽度。当全部文本框占用的宽度加起来未超过一行就将Flex设置为FlexWrap.NoWrap。如果前几个文本框累计超过一行后面无需计算，直接将Flex设置为FlexWrap.NoWrap。
    
    import { MeasureUtils, UIContext, window } from '@kit.ArkUI';
    
    @Entry
    @Component
    struct FlexPage2 {
      @State textList: string\[\] \= \['文本XXX', '文本XXXXX', '文本XXXXXX', '文本XXXXXXX', '文本XX', '文本X'\];
      @State isWarp: boolean \= false;
      flexWidth: number \= 0;
      uiContext: UIContext \= this.getUIContext();
      measureUtils: MeasureUtils \= this.getUIContext().getMeasureUtils();
    
      aboutToAppear(): void {
        window.getLastWindow(this.getUIContext().getHostContext(), (err, data) \=\> {
          data.setWindowLayoutFullScreen(true); _// 设置沉浸式布局_
          let properties \= data.getWindowProperties(); _// 获取当前窗口的属性_
          let windowWidth \= properties.windowRect.width; _// 获取当前窗口宽度_
          this.flexWidth \= windowWidth \- this.uiContext.vp2px(20 \* 2); _// 计算Flex组件的最大宽度，单位px_
          this.setFlexWrap(this.textList);
        });
      }
    
     _ // 设置是否换行_
      setFlexWrap(textList: string\[\]) {
        this.isWarp \= false; _// 默认不换行_
        let lineWidth \= this.flexWidth \- this.uiContext.px2vp(6 \* 2); _// Flex组件一行的最大宽度，单位px_
        let countWidth \= 0; _// 文本框占用的的宽度_
        textList.forEach((item) \=\> {
          if (this.isWarp \=== false) {
         _   // 计算文本的宽度_
            let textWidth \= this.measureUtils.measureText({
              textContent: item,
              fontSize: 12 _//_ _文本字体大小_
            });
            _// 累计文本框占用宽度，文本宽度+2\*文本框左右内边距+2\*文本框左右外边距_
            countWidth \= countWidth \+ textWidth \+ this.uiContext.vp2px(2 \* 12 \+ 2 \* 3);
           _ // 超过每行最大宽度，设置为换行_
            if (countWidth \>\= lineWidth) {
              this.isWarp \= true;
            }
          }
        });
      }
    
      build() {
        Column({ space: 10 }) {
          Column({ space: 10 }) {
            Text(\`计算首行能否放下全部文本，是否需要换行\`);
            Flex({
              justifyContent: FlexAlign.Start,
              wrap: this.isWarp ? FlexWrap.Wrap : FlexWrap.NoWrap, _//_ _根据状态变量设置是否换行_
              direction: FlexDirection.Row
            }) {
              ForEach(this.textList, (item: string) \=\> {
                Text(item)
                  .fontSize(12)
                  .maxLines(1)
                  .backgroundColor('#330A59F7')
                  .borderRadius(4)
                  .textOverflow({ overflow: TextOverflow.Ellipsis })
                  .ellipsisMode(EllipsisMode.END)
                  .margin(3) _// 文本框外边距3_
                  .padding({ left: 12, right: 12 }) _// 文本框左右内边距12_
                  .height(32);
              });
            }
            .padding(6) _// Flex组件内边距6_
            .backgroundColor('#ffffff')
            .width('auto');
          }.width('100%')
          .alignItems(HorizontalAlign.Start);
    
          Button('更换数据1')
            .onClick(() \=\> {
              this.textList \= \['文本XXXX', '文本X'\];
              this.setFlexWrap(this.textList);
            });
          Button('更换数据2')
            .onClick(() \=\> {
              this.textList \= \['文本XXXX', '文本X', '文本XXXXXXXXX', '文本XXXXXX', '文本XXX', '文本XX', '文本X', '文本XXX'\];
              this.setFlexWrap(this.textList);
            });
        }
        .padding({
          top: 50,
          left: 20,
          right: 20,
          bottom: 20
        }) _// 左右内边距20_
        .height('100%')
        .width('100%')
        .backgroundColor('#f1f3f5');
      }
    }
    
    运行效果图如下：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/38/v3/2SKGQ03vTkyE_RnEHcnKSg/zh-cn_image_0000002658801079.png?HW-CC-KV=V1&HW-CC-Date=20260709T133927Z&HW-CC-Expire=86400&HW-CC-Sign=143AA74384148D9337DAEB3C38C860BF8803F8F7CD93D2305E9D3E00AB67668D "点击放大")