为什么用 Flex

上次重构一个设置页面,我写了六层嵌套——Row套Column,Column再套Row,改一个间距要翻半天代码。同事看了一眼说:“你这代码是俄罗斯套娃吧?”

说实话,那一刻我意识到:不会用 Flex,写布局就是在折磨自己。

HarmonyOS7 的 Flex 弹性布局组件,真的是我用过最爽的布局方案之一。今天就来聊聊怎么用它告别嵌套地狱。

传统布局的痛点太明显了:

  • Row/Column 只有一个方向,遇到既需要水平又需要垂直的场景就得套娃
  • 对齐靠 margin 硬凑,改一处动全身
  • 自适应差,不同屏幕尺寸得写多套布局

Flex 组件把方向、对齐、分布、换行这些能力打包在一起,一个组件顶三个 Row/Column 嵌套

打个比方:Row/Column 就像只有直道的公路,Flex 是有立交桥的高速——想去哪,直接走,不用绕来绕去。

A hand-drawn doodle illustration on pure white pap

基础概念速览

先看看 Flex 跟 Row、Column 到底啥区别:

特性 Row Column Flex
主轴方向 水平 垂直 自由指定
子组件对齐 单一方向 单一方向 主轴+交叉轴
换行支持 支持 FlexWrap
比例分配 支持 flexGrow
嵌套需求 复杂布局需多层 复杂布局需多层 一层搞定

划重点:Flex 最大的优势是方向自由+换行+比例分配,这三个能力组合起来,能覆盖 90% 的布局场景。

实战案例一:等分布局

最常见的场景——几个按钮等分一行空间。

A hand-drawn doodle illustration on pure white pap

@Entry
@Component
struct EqualLayout {
  build() {
    Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
      ForEach(['首页', '发现', '消息', '我的'], (item: string) => {
        Text(item)
          .width('25%')
          .height(48)
          .textAlign(TextAlign.Center)
          .backgroundColor('#f1f1f1')
          .borderRadius(8)
      })
    }
    .width('100%')
    .height(56)
    .padding({ left: 16, right: 16 })
  }
}

关键代码讲解:

  • direction: FlexDirection.Row —— 指定主轴方向为水平,子组件从左到右排列
  • alignItems: ItemAlign.Center —— 交叉轴(这里是垂直方向)居中对齐
  • .width('25%') —— 每个子组件占 25%,四个刚好等分

用 Row 也能做等分,但 Flex 的好处是——后续要加对齐、间距,不用改结构,加个属性就行。

实战案例二:比例布局

不是所有场景都等分,比如侧边栏占 1 份,内容区占 3 份。这时候 flexGrow 就派上用场了。

@Entry
@Component
struct RatioLayout {
  build() {
    Flex({ direction: FlexDirection.Row }) {
      Text('侧边栏')
        .flexGrow(1)
        .height('100%')
        .backgroundColor('#e8e8e8')
        .textAlign(TextAlign.Center)

      Text('内容区')
        .flexGrow(3)
        .height('100%')
        .backgroundColor('#ffffff')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height(400)
  }
}

A hand-drawn doodle illustration on pure white pap

关键代码讲解:

  • .flexGrow(1) —— 侧边栏占 1 份剩余空间
  • .flexGrow(3) —— 内容区占 3 份剩余空间
  • 两者比例 1:3,不管屏幕多宽,比例永远一致

说白了,flexGrow 就是按比例瓜分剩余空间的"分蛋糕"机制。谁设的数字大,谁分得多。如果某个组件不设 flexGrow,它就只占自身内容大小,不参与分蛋糕。

实战案例三:换行布局

标签列表、商品筛选这类场景——标签数量不确定,一行放不下要自动换行。这是 Row 做不到的。

@Entry
@Component
struct WrapLayout {
  @State tags: string[] = [
    'ArkTS', 'ArkUI', 'Flex', '布局', '组件',
    '状态管理', '导航', '动画', '手势', '网络请求'
  ]

  build() {
    Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
      ForEach(this.tags, (tag: string) => {
        Text(tag)
          .height(36)
          .fontSize(14)
          .padding({ left: 16, right: 16 })
          .margin({ right: 8, bottom: 8 })
          .backgroundColor('#f0f0f0')
          .borderRadius(18)
      })
    }
    .width('100%')
    .padding(16)
  }
}

关键代码讲解:

  • wrap: FlexWrap.Wrap —— 开启换行,子组件超出宽度自动换到下一行
  • .margin({ right: 8, bottom: 8 }) —— 标签间距用 margin 控制,简单直接
  • FlexWrap.NoWrap(默认)不换行,子组件会被压缩或溢出

这个换行能力是 Flex 的杀手级功能。 之前用 Row 做标签列表,要么写死每行几个,要么自己算换行逻辑——现在一个属性搞定。

踩坑记录

用 Flex 踩过的几个坑,分享出来帮你避雷:

  1. flexGrow 和 width 同时设会冲突

    设了 flexGrow 就别再设固定 width,否则 flexGrow 会被忽略。这是最容易犯的错。

  2. alignItems 和子组件 alignSelf 别搞混

    alignItems 是 Flex 容器级别的对齐,所有子组件统一生效;alignSelf 是子组件级别的,可以覆盖容器的 alignItems。需要某个子组件特殊对齐时用 alignSelf

  3. FlexDirection.Reverse 的坑

    FlexDirection.RowReverse 会让子组件从右到左排列,但 ForEach 的顺序不变,视觉顺序和逻辑顺序相反,处理点击事件时要小心。

  4. 嵌套 Flex 性能没问题

    两层 Flex 嵌套是完全 OK 的,别为了"避免嵌套"硬把所有逻辑塞一层。合理嵌套 > 强行平铺

写在最后

Flex 组件本质上就是 HarmonyOS7 版的 CSS Flexbox,概念完全一致。如果你有 Web 开发经验,上手基本零成本。没有也没关系,记住这三个核心:

  • direction —— 子组件往哪个方向排
  • justifyContent —— 主轴怎么分布
  • alignItems —— 交叉轴怎么对齐

掌握这三个,日常布局够用了。遇到换行和比例分配的场景,Flex 就是最佳选择。

别再写 Row 套 Column 的俄罗斯套娃了,试试 Flex,你会回来谢我的。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐