HarmonyOS ArkUI 布局系统线性、弹性、层叠、栅格怎么选
ArkUI 布局系统:线性、弹性、层叠、栅格怎么选
布局决定组件在哪里
组件"长什么样"是组件属性的事,组件"放在哪"是布局的事。ArkUI 提供了多种布局容器,每种解决一类排列问题。选对布局,界面适配就顺;选错布局,写一堆 margin 硬调位置,换个屏幕就乱。
线性布局 Column / Row
最基础的布局:Column 纵向排列,Row 横向排列。
@Entry
@Component
struct LinearDemo {
build() {
Column({ space: 10 }) { // space:子组件间距
Text('第一行')
Text('第二行')
Text('第三行')
}
.padding(16)
}
}
线性布局的核心属性是对齐方式:
Column({ space: 10 }) {
Text('子组件 A')
Text('子组件 B')
}
.justifyContent(FlexAlign.Center) // 主轴(纵向)对齐:居中
.alignItems(HorizontalAlign.Center) // 交叉轴(横向)对齐:居中
justifyContent 控制主轴(Column 是纵向,Row 是横向),alignItems 控制交叉轴。两者配合能实现大部分居中、分散需求。
弹性布局 Flex
Flex 是线性布局的增强版,子组件可以弹性伸缩。当需要"占满剩余空间"或"按比例分配"时用它:
@Entry
@Component
struct FlexDemo {
build() {
Flex({ direction: FlexDirection.Row, wrap: FlexWrap.NoWrap }) {
Text('固定宽度')
.width(100)
Text('弹性占满剩余')
.flexGrow(1) // 占满剩余空间
Text('固定宽度')
.width(100)
}
.padding(16)
}
}
flexGrow(1) 让中间组件占满剩余空间。这在导航栏(左右按钮中间标题)场景非常常用:
Row() {
Image($r('app.media.back')).width(24).height(24) // 左侧返回
Text('页面标题')
.fontSize(18)
.layoutWeight(1) // 占满中间,实现标题居中
.textAlign(TextAlign.Center)
Image($r('app.media.more')).width(24).height(24) // 右侧更多
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
layoutWeight 是 Row/Column 里分配剩余空间的属性,配合 flexGrow 效果类似。
层叠布局 Stack
Stack 让子组件叠在一起,后声明的在上面。角标、悬浮按钮、图片上的文字都用它:
@Entry
@Component
struct StackDemo {
build() {
Stack({ alignContent: Alignment.TopEnd }) { // 对齐方式:右上角
// 底层:图片
Image($r('app.media.avatar'))
.width(80).height(80)
.borderRadius(40)
// 顶层:角标
Text('9')
.width(20).height(20)
.fontSize(12)
.fontColor(Color.White)
.backgroundColor(Color.Red)
.borderRadius(10)
.textAlign(TextAlign.Center)
}
}
}
alignContent 指定所有子组件的对齐位置,Alignment.TopEnd 是右上角。角标在头像上的遮罩场景用 Stack 最合适。
相对布局 RelativeContainer
相对布局让子组件相对其他组件或容器定位。在需要"组件 B 在组件 A 下方 10vp"这种相对关系时使用:
@Entry
@Component
struct RelativeDemo {
build() {
RelativeContainer() {
Text('标题')
.id('title') // 给组件设置 id
.fontSize(20)
Button('操作按钮')
.id('btn')
.alignRules({
bottom: { anchor: 'title', align: VerticalAlign.Bottom },
left: { anchor: '__container__', align: HorizontalAlign.Start }
})
}
.height(200)
.width('100%')
}
}
alignRules 定义对齐规则,anchor 指向参照组件的 id(__container__ 是容器自身)。相对布局语法相对繁琐,能用线性/弹性布局解决就别用它。
栅格布局 GridRow / GridCol
栅格布局把界面分成 12 列,组件占几列灵活分配。多设备适配的响应式场景用它:
@Entry
@Component
struct GridRowDemo {
build() {
GridRow({ columns: 12, gutter: 10 }) { // 12 列,列间距 10
GridCol({ span: 6 }) { // 占 6 列(一半)
Text('左侧').height(100).backgroundColor('#FFE0E0').width('100%')
}
GridCol({ span: 6 }) { // 占 6 列(一半)
Text('右侧').height(100).backgroundColor('#E0E0FF').width('100%')
}
}
.padding(16)
}
}
栅格布局的优势是响应式——可以针对不同屏幕宽度设置不同的列分配合(xs、sm、md、lg` 断点),实现一套代码适配手机、平板。
布局选型指南
需求 → 布局
────────────────────────────────────────
子组件垂直排列 → Column
子组件水平排列 → Row
需要弹性伸缩/占满剩余 → Flex / layoutWeight
组件叠加(角标、悬浮) → Stack
组件相对定位 → RelativeContainer
响应式多列分配 → GridRow / GridCol
长列表/宫格 → List / Grid(见上一篇)
嵌套布局:用例子理解
真实界面很少有单一布局,都是嵌套的。一个常见的"设置项"界面:
@Entry
@Component
struct SettingsDemo {
build() {
Column() {
// 设置项:左侧文字 + 右侧箭头
Row() {
Text('账号与安全')
.fontSize(16)
.layoutWeight(1) // 占满左侧
Image($r('app.media.arrow_right'))
.width(20).height(20)
}
.height(56)
.padding({ left: 16, right: 16 })
}
.width('100%')
}
}
每个设置项是横向 Row,左边文字用 layoutWeight 占满,右边放箭头。外层是纵向 Column 堆叠多个设置项。这个模式几乎每个 App 都有。
布局的几条经验
-
优先考虑弹性伸缩。硬编码
width(300)换屏就出问题,用layoutWeight/flexGrow让组件自适应,适配性更好。 -
居中需求分场景。单轴居中用
justifyContent/alignItems,组件本身居中且是唯一子组件时可以用Stack+alignContent。 -
space和gutter控制间距。别每个子组件都写 margin,容器级的space(线性/List)或 GridRow 的gutter统一控制间距更干净。 -
嵌套别太深。布局容器套三层以上就应该考虑拆自定义组件,深嵌套既难维护也影响布局性能。
-
栅格布局别滥用。简单的左右分栏用 Row +
layoutWeight就够,只有真正需要响应式多列分配时才上GridRow。
更多推荐

所有评论(0)