《多级标签并行筛选》一、Flex弹性布局使用指南
HarmonyOS ArkUI 弹性布局(Flex)从入门到实战完整指南
本文详细介绍 HarmonyOS ArkUI 中 Flex 弹性布局的使用方法,涵盖核心概念、属性配置、常见场景和完整示例代码,适合 HarmonyOS 开发者快速上手。
效果
一、前言
在 HarmonyOS ArkUI 开发中,布局是构建界面的基石。当我们面对多行标签排列、自适应导航栏、剩余空间分配等需求时,传统的 Row/Column 线性布局往往力不从心——需要手动拆分多行、计算宽度,代码冗余且不易维护。
Flex 弹性布局正是解决这类问题的利器。它提供了方向控制、自动换行、空间分配、交叉轴对齐等丰富能力,让复杂排列需求变得简洁直观。
本文将从基础概念讲起,逐步深入到实际案例,帮助你全面掌握 Flex 布局。
二、Flex 基础概念
2.1 什么是 Flex 布局
Flex 布局是一种一维布局模型,能够在主轴方向上灵活分配子组件的空间和间距。其核心概念包括:
| 概念 | 说明 |
|---|---|
| 主轴(Main Axis) | 子组件排列的主要方向,由 direction 属性决定 |
| 交叉轴(Cross Axis) | 垂直于主轴的方向 |
| Flex 容器 | 使用 Flex() 创建的布局容器 |
| Flex 子项 | 容器内的直接子组件 |
2.2 Flex 容器创建方式
Flex 容器有两种创建方式:
// 方式一:使用 Flex 组件(推荐)
Flex() {
Text('子项1')
Text('子项2')
}
// 方式二:使用 .flexDirection() 修饰符
Row() {
Text('子项1')
Text('子项2')
}
.flexDirection(FlexDirection.Row)
建议:在大多数场景下使用
Flex()组件更直观,因为它提供了完整的 Flex 属性配置。
三、核心属性详解
3.1 direction — 主轴方向
控制子组件的排列方向:
Flex({ direction: FlexDirection.Row }) {
// 水平排列(默认)
}
Flex({ direction: FlexDirection.Column }) {
// 垂直排列
}
Flex({ direction: FlexDirection.RowReverse }) {
// 水平反向排列
}
Flex({ direction: FlexDirection.ColumnReverse }) {
// 垂直反向排列
}
3.2 wrap — 换行控制
控制子组件超出主轴时是否换行:
| 值 | 说明 |
|---|---|
FlexWrap.NoWrap |
不换行(默认),子项可能被压缩 |
FlexWrap.Wrap |
换行,新行向交叉轴正方向排列 |
FlexWrap.WrapReverse |
换行,新行向交叉轴反方向排列 |
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(tagList, (tag: string) => {
Text(tag)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.backgroundColor('#F2F3F5')
.borderRadius(16)
})
}
适用场景:标签云、技能列表、分类筛选等多行排列场景。
3.3 justifyContent — 主轴对齐
控制子组件在主轴上的分布方式:
| 值 | 说明 |
|---|---|
FlexAlign.Start |
从起始端开始排列(默认) |
FlexAlign.Center |
居中对齐 |
FlexAlign.End |
从末端开始排列 |
FlexAlign.SpaceBetween |
两端对齐,子项间距相等 |
FlexAlign.SpaceAround |
每个子项两侧间距相等 |
FlexAlign.SpaceEvenly |
所有间距(包括两端)完全相等 |
Flex({ justifyContent: FlexAlign.SpaceBetween }) {
Text('左侧')
Text('中间')
Text('右侧')
}
.width('100%')
3.4 alignItems — 交叉轴对齐
控制子组件在交叉轴上的对齐方式:
Flex({ alignItems: ItemAlign.Center }) {
// 交叉轴居中对齐
}
Flex({ alignItems: ItemAlign.Stretch }) {
// 交叉轴拉伸填充(子项未设置交叉轴尺寸时生效)
}
3.5 alignContent — 多行对齐
仅在多行 Flex 布局(wrap 不为 NoWrap)中生效,控制行与行之间的分布:
Flex({
wrap: FlexWrap.Wrap,
alignContent: FlexAlign.Start
}) {
// 多行排列,行与行之间从交叉轴起始端开始排列
}
3.6 space — 子项间距
使用 LengthMetrics 精确设置主轴和交叉轴间距:
import { LengthMetrics } from '@kit.ArkUI';
Flex({
space: {
main: LengthMetrics.vp(12), // 主轴间距 12vp
cross: LengthMetrics.vp(8) // 交叉轴间距 8vp
}
}) {
// 子项之间自动添加间距
}
四、子项弹性属性
Flex 子项可以设置弹性属性,控制其在主轴方向上的尺寸行为:
4.1 flexGrow — 剩余空间分配
Flex({ direction: FlexDirection.Row }) {
Text('固定')
.width(80)
Text('弹性填充')
.flexGrow(1) // 占据剩余空间
.height(40)
}
.width('100%')
当多个子项都设置了 flexGrow 时,剩余空间按比例分配。
4.2 flexShrink — 空间不足时压缩
Flex({ direction: FlexDirection.Row }) {
Text('长文本内容可能会超出容器')
.flexShrink(1) // 允许压缩
.flexBasis(200)
Text('固定')
.width(80)
}
.width('100%')
4.3 flexBasis — 主轴基准尺寸
Flex({ direction: FlexDirection.Row }) {
Text('基准100')
.flexBasis(100) // 主轴基准宽度 100
Text('基准200')
.flexBasis(200) // 主轴基准宽度 200
}
注意:
flexBasis在主轴方向上会覆盖width/height设置。
4.4 alignSelf — 子项独立对齐
子项可以覆盖容器的 alignItems 设置:
Flex({ alignItems: ItemAlign.Center }) {
Text('居中')
Text('顶部对齐')
.alignSelf(ItemAlign.Start)
Text('底部对齐')
.alignSelf(ItemAlign.End)
}
.height(100)
五、完整示例:标签筛选组件
下面通过一个实际案例,展示 Flex 布局在标签筛选场景中的应用:
@ObservedV2
class TagItem {
@Trace label: string = '';
@Trace selected: boolean = false;
constructor(label: string) {
this.label = label;
}
}
@Entry
@ComponentV2
struct FlexTagDemo {
@Local tags: TagItem[] = [
new TagItem('全部'), new TagItem('推荐'), new TagItem('热门'),
new TagItem('最新'), new TagItem('收藏'), new TagItem('关注'),
new TagItem('排行榜'), new TagItem('精选')
];
toggleTag(tag: TagItem): void {
tag.selected = !tag.selected;
}
build() {
Column({ space: 20 }) {
Text('Flex 标签筛选示例')
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 使用 Flex 实现自动换行的标签排列
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.tags, (tag: TagItem) => {
Text(tag.label)
.fontSize(14)
.fontColor(tag.selected ? '#FFFFFF' : '#333333')
.backgroundColor(tag.selected ? '#4A90D9' : '#F2F3F5')
.borderRadius(20)
.padding({ top: 8, bottom: 8, left: 16, right: 16 })
.margin({ right: 10, bottom: 10 })
.onClick(() => {
this.toggleTag(tag);
})
}, (tag: TagItem) => tag.label)
}
.width('100%')
// 统计信息
Text(`已选择 ${this.tags.filter(t => t.selected).length} 个标签`)
.fontSize(14)
.fontColor('#999999')
}
.padding(20)
.width('100%')
.height('100%')
}
}
示例要点解析
FlexWrap.Wrap:标签超出容器宽度时自动换行,无需手动计算每行放几个。- 子项
margin:通过子项的margin控制标签之间的间距,兼容性更好(详见下方注意事项)。 @ObservedV2+@Trace:使用 V2 状态管理,标签选中状态变化能精确驱动 UI 更新。ForEach:动态渲染标签列表,配合稳定唯一的keyGenerator确保渲染效率。
六、Flex vs Row/Column 对比
| 场景 | 推荐布局 | 原因 |
|---|---|---|
| 单行/单列简单排列 | Row / Column | 结构清晰,属性简单 |
| 需要自动换行 | Flex | Row 不支持换行 |
| 需要剩余空间分配 | Flex | flexGrow/flexShrink 更灵活 |
| 需要多行对齐控制 | Flex | alignContent 提供行级控制 |
| 简单两端对齐 | Row + Blank() | 不需要引入 Flex 全部能力 |
七、最佳实践
- 优先使用
Flex处理多行流式布局:标签云、筛选项、分类导航等场景。 alignContent仅在多行时生效:单行 Flex 设置alignContent无效。flexBasis优先于width/height:在主轴方向上,flexBasis会覆盖对应尺寸属性。- 间距控制两种方式:使用
space属性需传入LengthMetrics类型值(如LengthMetrics.vp(8)),或直接在子项上设置margin控制间距,后者兼容性更好。 - 配合 V2 状态管理使用:
@ObservedV2+@Trace能精确追踪子项状态变化,避免不必要的全量刷新。
八、总结
Flex 弹性布局是 ArkUI 中处理多方向、换行、空间分配场景的首选方案。掌握 direction、wrap、justifyContent、alignItems 四大核心属性,配合 flexGrow、flexShrink、flexBasis 子项弹性控制,能够轻松应对绝大多数复杂排列需求。
在实际项目中,建议遵循"简单排列用 Row/Column,复杂排列用 Flex"的原则,既保持代码简洁,又充分利用 Flex 的强大能力。
参考文档:弹性布局 (Flex)
更多推荐




所有评论(0)