《多级标签并行筛选》一、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),// 主轴间距 12vpcross: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)// 主轴基准宽度 100Text('基准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 布局在标签筛选场景中的应用:
@ObservedV2classTagItem{@Tracelabel:string='';@Traceselected:boolean=false;constructor(label:string){this.label=label;}}@Entry@ComponentV2struct FlexTagDemo{@Localtags:TagItem[]=[newTagItem('全部'),newTagItem('推荐'),newTagItem('热门'),newTagItem('最新'),newTagItem('收藏'),newTagItem('关注'),newTagItem('排行榜'),newTagItem('精选')];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)
