ArkUI 弹性布局(对照 Android):用 Flex 做可换行的筛选标签区

Row / Column 解决的是“沿一个方向排”。但在真实页面里,总有一类组件数量不稳定:筛选标签、兴趣标签、快捷入口、关键字 chips……它们的共同点是:

  • 文案长度不固定(会撑开宽度)。
  • 数量不固定(可能 3 个,也可能 30 个)。
  • 需要在窄屏自动换行,在宽屏尽量铺满。

这就是 Flex 的主战场。

本文只解决一个问题:做一个可复用的“筛选标签区”,标签会自动换行,且在不同屏宽下能维持稳定的对齐与间距。 不覆盖:瀑布流卡片(更适合 Grid)、长列表虚拟化(List)、自定义布局算法与动画排布(属于后续工程化主题)。

先明确我们要的 UI 行为

一个简单的场景:搜索结果页的筛选条(多标签、可点、可换行)。

窄屏:一行放不下 → 自动换行(wrap)
宽屏:仍保持行内间距一致,不挤成一团(spacing / justify)

关键点不在“怎么画一个按钮”,而在“容器怎么分配空间”。

ArkUI:用 Flex + Wrap 写筛选标签区

先看 ArkUI 版本。核心是两件事:

1. Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) 让子组件可以换行。 2. 用 .margin(...) 给每个标签一个稳定的外边距(比在容器上“猜 gap”更直观)。

@Component
struct FilterChips {
  private chips: string[] = ['推荐', '最新', '最热', '可下载', '已购买', '含折扣', '可退款', '48 小时内更新']

  build() {
    Flex({
      direction: FlexDirection.Row,
      wrap: FlexWrap.Wrap,
      justifyContent: FlexAlign.Start,
      alignItems: ItemAlign.Center,
      alignContent: FlexAlign.Start
    }) {
      ForEach(this.chips, (label: string) => {
        Text(label)
          .fontSize(12)
          .fontColor('#111827')
          .padding({ left: 12, right: 12, top: 8, bottom: 8 })
          .backgroundColor('#F3F4F6')
          .borderRadius(999)
          .margin({ right: 10, bottom: 10 })
      })
    }
    .width('100%')
  }
}

Pasted image 20260524230156

读这段代码时可以只盯住 3 个属性:

  • wrap: FlexWrap.Wrap:决定“放不下就换行”。如果你看到一堆标签被压缩成不可读的样子,第一反应先看 wrap。
  • justifyContent:决定每一行在主轴(横向)怎么分布。想“靠左挤在一起”用 Start;想“尽量拉开”用 SpaceBetween
  • alignContent:决定多行整体在交叉轴(纵向)怎么摆放(多数情况下 Start 就够用)。

> 经验:先把 wrap 跑通,再谈“怎么铺满”。很多页面的真实目标是“可读 + 可点”,不是“强行对齐成一条直线”。

Android(Compose):对应的写法是什么?

在 Android 侧,遇到“可换行的 chips”,最常见有两条路:

  • Compose:用 FlowRow(把“换行”交给布局容器)。
  • View/XML:用 Google 的 FlexboxLayout(把“换行 + 对齐”交给容器实现)。

下面是 Compose 的思路(伪代码级别,重点在布局意图):

FlowRow(
  mainAxisSpacing = 10.dp,
  crossAxisSpacing = 10.dp
) {
  chips.forEach { label ->
    Text(
      text = label,
      modifier = Modifier
        .clip(RoundedCornerShape(999.dp))
        .background(Color(0xFFF3F4F6))
        .padding(horizontal = 12.dp, vertical = 8.dp)
    )
  }
}

你会发现:ArkUI 的 .margin({ right, bottom }),在 Compose 侧通常用容器 spacing 来表达;两端本质一样——先让容器具备换行能力,再定义稳定间距

一张对比表:Flex / FlowRow / FlexboxLayout 要对齐的不是“名字”,是“行为”

你要的行为 ArkUI(Flex) Android Compose Android View/XML
一行放不下自动换行 wrap: FlexWrap.Wrap FlowRow FlexboxLayout(wrap)
每行靠左 / 拉开分布 justifyContent(FlexAlign.Start/SpaceBetween) Arrangement.Start/SpaceBetween(思路一致) justifyContent(概念一致)
多行整体如何堆叠 alignContent(FlexAlign.Start/Center/...) Alignment / 容器约束 alignContent(概念一致)
子项纵向对齐 alignItems(ItemAlign.Center/Start) Alignment.CenterVertically alignItems(概念一致)
间距稳定(可读/可点) 子项 .margin(...) mainAxisSpacing/crossAxisSpacing layout_margin / item decorator

如果你把“API 名字对上”当目标,会越写越乱;把“行为对上”当目标,迁移就会变得很线性。

常见坑:为什么我写了 Flex 还是不好用?

1) 把“铺满”当成第一目标 筛选标签区的第一目标是“可读、可点、可扫视”。SpaceBetween 虽然能“拉开”,但当某行只有 2 个标签时,会造成视觉割裂。通常先用 Start + 稳定间距。

2) 标签被压到看不清 如果你看到标签文字被挤压、换行不符合预期,先确认:你是不是还在用 Row?或者 Flex 里没开 wrap

3) 把“多端适配”留到最后 今天 Android 侧官方已经明确 UI 开发进入 “Compose-first”,并持续把多形态适配(窗口、折叠屏、平板)推到主线能力里。对应到布局层,像这种“可换行 + 可扩展布局”区域,越早用正确的容器表达,后面越不需要返工。

参考素材(当天高质量链接)

  • HarmonyOS 官方文档:弹性布局(Flex)
  • https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-layout-development-flex-layout
  • Android Developers Blog:Android UI Development is Compose First
  • https://android-developers.googleblog.com/2026/05/android-ui-development-is-compose-first.html
  • Android 官方文档:Adaptive apps(多形态与响应式 UI 的入口)
  • https://developer.android.com/develop/adaptive-apps

// Kai@CodeHubble // 观测坐标:Android-HarmonyOS/2026-05-20

上一篇
下一篇