用 Row 拼工具栏,左右两端怎么都对不齐
你一定遇到过这个场景:做一个顶部工具栏,左边一个返回按钮,右边一个分享按钮,中间是标题。你用 Row 横着一排,结果发现两个按钮黏在一起,怎么调都没法让它们一个靠最左、一个靠最右。再比如做一组标签,文章标签、商品规格,标签一多就溢出屏幕,你却没法让它自动换到下一行。
很多人这时候开始用空白占位、手动算宽度,越写越乱。其实在华为鸿蒙系统的 ArkUI 框架里,有一个组件专门解决这类问题,它叫 Flex。今天用华为仓颉编程语言讲清楚:Flex 不是可有可无的高级货,它是当 Row、Column 不够用时,那条最关键的缓冲带。
先搞懂:Flex 和 Row、Column 到底差在哪
Row 和 Column 你应该已经会了,一个横着排、一个竖着排。Flex 看起来也是排列子组件,那它凭什么单独存在?
差别在三件事上。第一,Row、Column 排不下也不会换行,会直接挤出去;Flex 能让子组件自动折到下一行。第二,Row、Column 对齐方式比较有限;Flex 能把剩余空间按几种规则灵活分配,比如两端对齐、等间距分布。第三,有个容易忽略的默认行为:Flex 的主轴不设置时会撑满父容器,而 Row、Column 默认是跟着子组件大小走。
所以选型原则很清楚:普通的横排竖排,优先用 Row、Column,因为它们更轻快;一旦需要换行,或者需要复杂的空间分配,就换 Flex。
import kit.ArkUI.*

Flex 的六个参数,决定了它的全部能力
Flex 的能力都藏在构造函数的参数里。一次看全:
public init(direction!: ?FlexDirection = None, wrap!: ?FlexWrap = None, justifyContent!: ?FlexAlign = None, alignItems!: ?ItemAlign = None, alignContent!: ?FlexAlign = None, child!: () -> Unit = {=>})
挑最常用的三个理解:`direction` 决定主轴方向,是横排还是竖排;`wrap` 决定排不下时换不换行;`justifyContent` 决定子组件沿主轴怎么对齐和分配空间。剩下的 `alignItems` 管交叉轴对齐,`alignContent` 管多行之间的对齐。
这里有个概念要先立住:主轴和交叉轴。如果是横排,主轴就是水平方向,交叉轴就是垂直方向;竖排则反过来。后面所有对齐都是围绕这两根轴展开的。
justifyContent:工具栏两端对齐就靠它
回到开头的工具栏问题。左右两端对齐,本质是主轴上的空间分配,这正是 `justifyContent` 的活儿。它取一个 FlexAlign 枚举,一共六个值:
·Start、Center、End:分别是靠首端、居中、靠尾端
·SpaceBetween:两端对齐,第一个贴最左,最后一个贴最右,中间均分空隙
·SpaceAround:每个子组件两侧的间距相等
·SpaceEvenly:所有间距完全相等,包括两端到容器边的距离
工具栏要的就是 SpaceBetween:
Flex(justifyContent: FlexAlign.SpaceBetween) { Button("返回") Text("标题") Button("分享") } .width(100.percent) .padding(10)
一行设置,返回按钮自动贴左、分享按钮自动贴右、标题居中,剩余空间被均匀推开。再也不用手动算宽度或塞空白占位了。

alignItems:交叉轴对齐,解决高低不齐
主轴对齐解决了“横向怎么分布”,那“纵向怎么对齐”呢?这是交叉轴的事,由 `alignItems` 控制,取 ItemAlign 枚举。
常用的几个值:Start 顶部对齐、Center 垂直居中、End 底部对齐、Stretch 拉伸填满、Baseline 文字基线对齐。
做工具栏时通常配 Center,让大小不一的按钮和文字在垂直方向居中,看起来才整齐:
Flex(justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center) { Button("返回") Text("标题") Button("分享") } .width(100.percent) .height(56)
`justifyContent` 管横向分布,`alignItems` 管纵向对齐,两个一配,一个标准的导航栏就成型了。
wrap:标签流自动换行,这是 Row 给不了的
现在解决第二个痛点,标签流。一堆标签,一行放不下要自动折行。Row 做不到这件事,但 Flex 只要打开 `wrap` 就行。
`wrap` 取 FlexWrap 枚举,三个值:NoWrap 不换行(默认)、Wrap 正常换行、WrapReverse 反向换行。做标签流用 Wrap:
Flex(wrap: FlexWrap.Wrap) { Text("华为仓颉") .padding(8) .margin(4) .backgroundColor(0xF5DEB3) Text("华为鸿蒙系统") .padding(8) .margin(4) .backgroundColor(0xD2B48C) Text("弹性布局") .padding(8) .margin(4) .backgroundColor(0xF5DEB3) // 更多标签 } .width(100.percent)
标签一多,Flex 自动把放不下的折到下一行,不会溢出屏幕。这就是为什么搜索历史、商品规格、兴趣选择这类界面,几乎都是用 Flex 做的。

一个要记住的代价:Flex 有二次布局
Flex 这么灵活,是不是该全用它?这里要诚实地说一个性能细节。
官方文档明确提到,Flex 在渲染时存在二次布局过程。简单说,它要先量一遍、再排一遍,比 Row、Column 多一道工序。所以在对性能有严格要求的场景,比如长列表里反复出现的列表项,建议优先用 Row、Column。
这恰恰呼应了“缓冲带”这个定位:Flex 不是用来替代 Row、Column 的,它是在它们能力到顶时顶上来的那一层。日常布局用轻量的 Row、Column,遇到换行和复杂分配,再请 Flex 出场。
怎么选:一张决策清单

最后给你一份选型清单,照着判断就行:
·只是简单横排或竖排,子组件不会溢出 → 用 Row、Column
·需要两端对齐、等间距分布这类空间分配 → 用 Flex 的 `justifyContent`
·子组件可能一行放不下、要自动换行 → 用 Flex 的 `wrap`
·在高频刷新的列表项内部、性能敏感 → 退回 Row、Column
把这套判断记牢,你就不会再纠结到底该用哪个容器。Flex 用对了地方,复杂布局会变得异常省心。

夜雨聆风