


一、引言
HarmonyOS NEXT 作为鸿蒙生态的里程碑版本,从系统底层剔除了 Android 代码,实现了真正意义上的「纯鸿蒙」。与之配套的 ArkUI 框架提供了一套完整的声明式 UI 布局体系,其核心设计理念是 「弹性」—— 即布局容器和子组件能够根据可用空间自动调整尺寸和排列方式,从而适配从智能手表(320px)到折叠屏展开态(1440px)的各种屏幕尺寸。
ArkUI 的布局体系可以归纳为三大类容器:
- Flex 弹性容器:一维排列,支持水平/垂直/反向四种方向,弹性伸缩(flexGrow/flexShrink/flexBasis)
- Stack 层叠容器:Z 轴堆叠,支持 9 种对齐位置,适合盖层/浮层场景
- Grid 网格容器:二维排列,通过 columnsTemplate/rowsTemplate 精确控制行列结构
本文将以一个完整的鸿蒙应用项目为依托,逐一深入讲解这三大类容器的 12 种布局模式,包含完整的代码示例、布局公式和典型应用场景。
二、项目架构与入口
2.1 应用入口 EntryAbility
鸿蒙应用的入口是 UIAbility 的子类,通过 onWindowStageCreate 生命周期加载首页面:
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
const DOMAIN = 0x0000;
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'EnglishApp', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(DOMAIN, 'EnglishApp', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(DOMAIN, 'EnglishApp', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/GridFixedColDemo', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'EnglishApp',
'Failed to load content: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'EnglishApp', 'Succeeded in loading content.');
});
}
onWindowStageDestroy(): void { /* ... */ }
onForeground(): void { /* ... */ }
onBackground(): void { /* ... */ }
}
要点:
loadContent参数为页面路径(不含.ets后缀)- 框架自动解析路径并加载对应页面
hilog来自@kit.PerformanceAnalysisKit,是鸿蒙的日志工具
2.2 页面结构通用模板
每个演示页面都采用一致的骨架结构:
最外层 Column(height:100%, width:100%)
├── 顶部标题栏(蓝底白字,固定高度)
└── Scroll 滚动区
└── 内层 Column
├── DemoSection 演示区块 1
├── DemoSection 演示区块 2
├── ...
└── TechPanel 技术说明面板
三、Column 主轴对齐布局
3.1 核心概念
Column 是 ArkUI 中最基础的垂直布局容器。它的主轴(Main Axis)方向是「从上到下」,交叉轴(Cross Axis)方向是「从左到右」。justifyContent 控制主轴方向的对齐方式,alignItems 控制交叉轴方向的对齐方式。
3.2 6 种对齐值
| 枚举值 | 效果 | 类比 CSS |
|---|---|---|
FlexAlign.Start | 顶部起始排列 | flex-start |
FlexAlign.Center | 垂直居中 | center |
FlexAlign.End | 底部对齐 | flex-end |
FlexAlign.SpaceBetween | 两端对齐,子项间等距 | space-between |
FlexAlign.SpaceAround | 每个子项左右间距相等 | space-around |
FlexAlign.SpaceEvenly | 子项间及两端间距相等 | space-evenly |
3.3 代码实现
@Entry
@Component
struct ColumnStartPage {
private readonly infoList: InfoItem[] = [
{ title: '📌 系统通知', desc: '您的鸿蒙应用已通过安全检测。' },
{ title: '📊 数据报告', desc: '本周活跃用户增长 12%。' },
{ title: '⚙️ 版本更新', desc: 'v3.2.0 发布。' },
{ title: '🎯 优化建议', desc: '检测到 3 处可优化项。' },
];
build() {
Column() {
// 标题区
Column() { /* ... */ }
.backgroundColor('#2d5f8a')
// ★ 核心:Column + justifyContent(Start) ★
Column() {
ForEach(this.infoList, (item, idx) => {
InfoCard({ item, index: idx })
})
}
.alignItems(HorizontalAlign.Start) // 交叉轴左对齐
.justifyContent(FlexAlign.Start) // ★ 主轴从顶部开始 ★
.width('100%')
.layoutWeight(1) // 撑满剩余高度
}
.width('100%').height('100%')
.backgroundColor('#eef2f7')
}
}
关键理解:layoutWeight(1) 让 Column 占满父容器剩余高度,这样才能让 justifyContent 的效果可见。如果 Column 高度等于内容高度,Start/Center/End 看不出区别。
四、Flex 弹性容器与四种 flexDirection
Flex 是比 Column/Row 更底层、更灵活的弹性容器。Column 等效于 flexDirection(FlexDirection.Column) 的 Flex 容器,Row 等效于 flexDirection(FlexDirection.Row) 的 Flex 容器。但 Flex 额外支持两种反向模式。
4.1 四种方向一览
| flexDirection 值 | 排列方向 | 代码首项位置 | 典型场景 |
|---|---|---|---|
FlexDirection.Row | 从左→右 | 最左侧 | 水平导航栏 |
FlexDirection.RowReverse | 从右→左 | 最右侧 | RTL语言界面 |
FlexDirection.Column | 从上→下 | 最顶部 | 表单/纵向列表 |
FlexDirection.ColumnReverse | 从下→上 | 最底部 | 聊天消息列表 |
4.2 Row 与 RowReverse 对比
// ★ Row:从左到右 ★
Flex() {
Text('A'), Text('B'), Text('C')
}
.flexDirection(FlexDirection.Row)
// 输出:[A] [B] [C]
// ★ RowReverse:从右到左 ★
Flex() {
Text('A'), Text('B'), Text('C')
}
.flexDirection(FlexDirection.RowReverse)
// 输出:[C] [B] [A] ← 代码在前的 A 显示在右侧
4.3 ColumnReverse 的聊天列表应用
ColumnReverse 最经典的场景是聊天消息列表——最新消息在底部,历史消息在上方:
Flex() {
// 最早的消息在代码顶部,显示在列表顶部
ChatBubble({ msg: '早上好!', isSelf: false })
ChatBubble({ msg: '下午三点开会。', isSelf: true })
// ★ 最新消息在代码最后 → 显示在最底部 ★
ChatBubble({ msg: '好的,准时到。', isSelf: false })
}
.flexDirection(FlexDirection.ColumnReverse)
容易混淆的点:
RowReverse只反转排列顺序,不反转每个组件内部的内容方向justifyContent(FlexAlign.Start)在 RowReverse 下等效于「右侧对齐」alignItems不受反向影响,始终控制交叉轴方向
五、Flex + Wrap 响应式卡片流
当子组件数量多到一行放不下时,普通的 Flex(不换行)会尝试压缩所有子组件以适应容器宽度。而在电商、图库等场景中,我们希望子组件在空间不足时自动「换行」到下一行——这就是 flexWrap(FlexWrap.Wrap) 的作用。
5.1 核心代码结构
Flex() {
ForEach(PRODUCTS, (product) => {
ProductCard({ product, cardSizeMode: this.cardSizeMode })
})
}
.flexDirection(FlexDirection.Row) // 主轴水平
.flexWrap(FlexWrap.Wrap) // ★ 允许换行(核心)★
.justifyContent(FlexAlign.Start) // 行内左对齐
.alignItems(ItemAlign.Start) // 交叉轴顶部对齐
.width('100%')
5.2 layoutWeight 实现等分
每个卡片组件使用 layoutWeight(1) 控制行内宽度比例:
@Component
struct ProductCard {
@Link cardSizeMode: number; // 0=小(3列) / 1=中(2列) / 2=大(1列)
build() {
Column() {
Text(this.product.emoji).fontSize(this.cardSizeMode === 2 ? 36 : 26)
Text(this.product.name)
.fontSize(this.cardSizeMode === 2 ? 18 : 14)
Text(`¥${this.product.price}`)
.fontSize(this.cardSizeMode === 2 ? 22 : 18)
.fontColor('#e74c3c')
}
.layoutWeight(1) // ★ 同一行中等分宽度 ★
.margin(6)
}
}
5.3 flexGrow vs layoutWeight
| 属性 | 分配对象 | 公式 |
|---|---|---|
flexGrow | 剩余空间(容器 − 所有子项内容尺寸) | 内容宽 + 剩余空间 × (growN / Σgrow) |
layoutWeight | 容器全部空间 | 容器宽 × (weightN / Σweight) |
在换行布局中,layoutWeight 更常用,因为每行独立计算权重分配,不受其他行子项内容宽度干扰。
5.4 @State 驱动密度切换
@State cardSizeMode: number = 0;
Row() {
ForEach([0, 1, 2], (mode: number) => {
Button(['紧凑(3列)', '适中(2列)', '宽大(1列)'][mode])
.layoutWeight(1)
.backgroundColor(this.cardSizeMode === mode ? '#2d5f8a' : '#e8ecf0')
.onClick(() => { this.cardSizeMode = mode; })
})
}
六、Flex + flexGrow 弹性增长
flexGrow 是弹性布局中最重要的单个属性。它定义了子组件在「剩余空间」中的分配比例。
6.1 核心公式
子项 N 的实际增长量 = 剩余空间 × (growN ÷ Σgrow)
其中:
剩余空间 = 容器主轴尺寸 − 所有子组件内容尺寸之和(或 flexBasis 之和)
Σgrow = 所有非零 flexGrow 值的总和
6.2 基础:单项填充
Flex() {
Text('A:grow(0)') // 不增长,只占内容宽度
Text('B:grow(0)') // 不增长
Text('C:grow(1)') // ★ 填充所有剩余空间 ★
}
.flexDirection(FlexDirection.Row)
.width('100%')
这是「固定左 + 固定右 + 弹性中间」布局模式的实现原理。
6.3 等比分配
// 1:1:1 → 三等分剩余空间
.grow(1) : .grow(1) : .grow(1)
// 每项 = 剩余空间 × 1/3
// 1:2:1 → 中间是两边的 2 倍
.grow(1) : .grow(2) : .grow(1)
// A = 剩余空间 × 1/4
// B = 剩余空间 × 2/4 = 1/2
// C = 剩余空间 × 1/4
6.4 垂直方向的页面骨架
Flex() {
Row() {}.flexGrow(0).height(48) // 顶部固定
Column() {}.flexGrow(1) // ★ 内容区弹性填充 ★
Row() {}.flexGrow(0).height(40) // 底部固定
}
.flexDirection(FlexDirection.Column)
.height('100%')
这是移动端最经典的页面布局模式,flexGrow(1) 让中间内容区自动填满头尾之外的所有剩余高度。
七、Flex + flexBasis 基准尺寸
flexBasis 设置子组件在「弹性分配前」的主轴初始尺寸,flexGrow/flexShrink 在此之上叠加作用。
7.1 flexBasis 取值
| 值 | 含义 | 示例 |
|---|---|---|
'auto' | 由内容或 width/height 决定 | .flexBasis('auto') |
'80px' | 固定初始尺寸 80vp | .flexBasis('80px') |
'33%' | 初始尺寸为容器主轴尺寸的 33% | .flexBasis('33%') |
7.2 最终尺寸公式
最终尺寸 = flexBasis + 增长量(grow) − 压缩量(shrink)
7.3 实战:三种典型布局模式
// ★ 模式1:固定左栏 + 弹性右栏 ★
Flex() {
Column() {}.flexBasis('80px').flexGrow(0) // 侧栏固定宽
Column() {}.flexBasis('auto').flexGrow(1) // 主区弹性填充
}
.flexDirection(FlexDirection.Row)
// ★ 模式2:三等分百分比布局 ★
Flex() {
Column() {}.flexBasis('33.3%').flexGrow(0)
Column() {}.flexBasis('33.3%').flexGrow(0)
Column() {}.flexBasis('33.3%').flexGrow(0)
}
.flexDirection(FlexDirection.Row)
// ★ 模式3:垂直页面骨架(basis+flexGrow 混合)★
Flex() {
Row() {}.flexBasis('56px').flexGrow(0) // 顶栏固定高
Column() {}.flexBasis('auto').flexGrow(1) // 内容区弹性
Row() {}.flexBasis('48px').flexGrow(0) // 底栏固定高
}
.flexDirection(FlexDirection.Column).height('100%')
7.4 flexBasis + flexShrink 压缩演示
当容器宽度不足以容纳所有子项的 flexBasis 之和时,flexShrink 控制各子项的压缩比例:
Flex() {
// A: shrink(0) → 不缩小,保持 100px
Box({ label:'A', basis:'100px', shrink:0 })
// B/C/D: shrink(1) → 各承担 1/3 溢出量
Box({ label:'B', basis:'100px', shrink:1 })
Box({ label:'C', basis:'100px', shrink:1 })
Box({ label:'D', basis:'100px', shrink:1 })
}
.flexDirection(FlexDirection.Row)
.width(300) // 4×100=400px > 300px,溢出 100px
// A:100px, B≈67px, C≈67px, D≈67px
八、Stack 层叠布局(四种对齐模式)
Stack 是 ArkUI 中的层叠容器——子组件沿 Z 轴堆叠而非沿 X/Y 轴排列。后写的子组件覆盖在先写的上方。alignContent 控制所有子组件整体的对齐位置。
8.1 9 种 Alignment 枚举
| 水平\垂直 | Top | Center | Bottom |
|---|---|---|---|
| Start | TopStart 左上 | Start 左中 | BottomStart 左下 |
| Center | TopCenter 上中 | Center 正中 | BottomCenter 下中 |
| End | TopEnd 右上 | End 右中 | BottomEnd 右下 |
8.2 TopStart(左上对齐)
所有子组件对齐到 Stack 容器的左上角:
Stack() {
StackBox({ w:200, h:150, color:'#5B9BD5', label:'底层' })
StackBox({ w:160, h:100, color:'#70AD47', label:'中层' })
StackBox({ w:100, h:80, color:'#FFC000', label:'★ 顶层' })
}
.alignContent(Alignment.TopStart)
.width('100%').height(160)
8.3 Top(顶部居中)
所有子组件水平居中、垂直贴顶:
Stack() {
// 底层:横条背景
Row() {}.width('100%').height(64).backgroundColor('#2d5f8a')
// 中层:标题文字(顶部居中)
Text('📢 系统通知').fontSize(16).fontColor('#ffffff')
// 顶层:关闭按钮(右上角,突破居中约束)
Text('✕').alignSelf(ItemAlign.End).margin({ top:8, right:14 })
}
.alignContent(Alignment.Top)
.width('100%').height(64)
8.4 Bottom(底部居中)
所有子组件水平居中、垂直贴底:
Stack() {
// 底层:播放器面板
Column() {}.width('100%').height(160).backgroundColor('#1a1a2e')
// 上层:歌曲信息
Row() { Text('🎵'), Text('歌名') }
// 最上层:控制按钮
Row() { Text('⏮'), Text('⏸'), Text('⏭') }
}
.alignContent(Alignment.Bottom)
.width('100%').height(170)
8.5 Overlay(层叠盖层 + ZIndex)
在图片上叠加文字、按钮、标签,并通过 ZIndex(n) 精确控制各层的前后关系:
Stack() {
// L1: 底层图片
ImageScreen()
// L2: 半透明蒙层(zIndex=1)
Column() {}.width('100%').height('100%')
.backgroundColor('#22000000').zIndex(1)
// L3: 左上标签(zIndex=2)
Text('👟 运动鞋').alignSelf(ItemAlign.Start)
.margin(10).zIndex(2)
// L4: 右上评分(zIndex=3)
Text('⭐ 4.8').alignSelf(ItemAlign.End)
.margin(10).zIndex(3)
// L5: 底部价格条(zIndex=5,最上层)
Row() { Text('¥ 1,299').fontColor('#e74c3c') }
.alignSelf(ItemAlign.End).width('100%')
.zIndex(5)
}
.alignContent(Alignment.TopStart)
ZIndex 规则:
ZIndex(n)数值越大,子组件越靠前(越在视觉上层)- 相同 ZIndex 时,后写的覆盖先写的
- 无 ZIndex 时默认值为 0
8.6 alignSelf 覆盖整体对齐
在 Stack 中,可以通过 alignSelf 让某个子组件突破整体对齐约束,单独对齐到不同位置:
Stack() {
Box('A:跟随') // 默认跟随 TopStart
Box('B:左上').alignSelf(ItemAlign.Start) // 覆盖为左上
Box('C:右上').alignSelf(ItemAlign.End) // 覆盖为右上
}
.alignContent(Alignment.Top)
8.7 position 精准定位
Stack() {
PositionDot({ x:'10%', y:'10%', label:'A(10%,10%)' })
PositionDot({ x:'50%', y:'30%', label:'B(50%,30%)' })
PositionDot({ x:'80%', y:'60%', label:'C(80%,60%)' })
}
.alignContent(Alignment.TopStart)
.position({x, y}) 以 Stack 左上角为原点,支持像素和百分比两种单位。
九、Grid 固定列网格布局
Grid 是 ArkUI 最强大的二维布局容器,通过 columnsTemplate 和 rowsTemplate 同时控制行和列的结构。
9.1 核心语法
Grid() {
GridItem() { /* 第1行第1列 */ }
GridItem() { /* 第1行第2列 */ }
GridItem() { /* 第1行第3列 → 自动换行到第2行 */ }
// ...更多 GridItem
}
.columnsTemplate('1fr 1fr 1fr') // ★ 三列等宽 ★
.columnsGap(8) // 列间距
.rowsGap(8) // 行间距
.width('100%')
9.2 fr 单位详解
fr(fraction)是 Grid 中按比例分配空间的核心单位:
| 模板 | 含义 |
|---|---|
'1fr 1fr 1fr' | 三列等宽,各占 1/3 |
'1fr 2fr 1fr' | 中间列是两侧的 2 倍 |
'80px 1fr 1fr' | 第一列固定 80px,后两列等分剩余 |
'1fr 1fr 1fr 1fr' | 四列等宽 |
9.3 混合列宽实战
Grid() {
ForEach(items, (item) => {
GridItem() {
Column() {
Text(item.label)
}.width('100%').height(56)
.backgroundColor(colors[idx]).borderRadius(8)
}
})
}
.columnsTemplate('80px 1fr 1fr') // ← 固定+弹性混合
.columnsGap(6).rowsGap(6)
.width('100%')
9.4 GridItem 跨列
Grid() {
// ★ 横幅:跨 3 列(占据整行宽度)★
GridItem() {
Text('🎉 限时特惠 · 全场满 300 减 50')
}
.columnStart(1).columnEnd(3) // 跨第1到第3列
// 普通商品卡片
ForEach(PRODUCTS, (product) => {
GridItem() { ProductCard(product) }
})
}
.columnsTemplate('1fr 1fr 1fr')
columnStart/columnEnd 从 1 开始编号。columnEnd(3) 表示到第 3 列结束,即占据第 1-3 列的宽度。
9.5 商品网格完整示例
const PRODUCTS = [
{ name:'蓝牙耳机', price:299, sold:18324, emoji:'🎧' },
{ name:'充电宝', price:99, sold:47531, emoji:'🔋' },
{ name:'智能手表', price:1299, sold:6592, emoji:'⌚' },
// ...更多商品
];
Grid() {
ForEach(PRODUCTS, (product) => {
GridItem() {
Column() {
Text(product.emoji).fontSize(28)
Text(product.name).fontSize(13).fontWeight(FontWeight.Bold)
Text(`¥${product.price}`).fontSize(18).fontColor('#e74c3c')
Text(`已售 ${product.sold}`).fontSize(10).fontColor('#999')
}
.width('100%').height(130)
.backgroundColor('#ffffff').borderRadius(10)
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(8).rowsGap(8)
.width('100%')
十、布局属性速查表
10.1 Flex 弹性属性
| 属性 | 作用于 | 默认值 | 取值 | 类比 CSS |
|---|---|---|---|---|
flexGrow | 子组件 | 0 | number(≥0) | flex-grow |
flexShrink | 子组件 | 1 | number(≥0) | flex-shrink |
flexBasis | 子组件 | 'auto' | number / string | flex-basis |
flexWrap | 容器 | NoWrap | NoWrap / Wrap | flex-wrap |
justifyContent | 容器 | Start | 6 种对齐值 | justify-content |
alignItems | 容器 | Stretch | 4 种对齐值 | align-items |
layoutWeight | 子组件 | 0 | number | 无直接对应 |
10.2 Stack 层叠属性
| 属性 | 作用 | 取值 |
|---|---|---|
alignContent | 控制所有子组件整体对齐 | 9 种 Alignment 枚举 |
alignSelf | 单个子组件突破整体对齐 | ItemAlign.Start / Center / End |
zIndex | 显式控制 Z 轴顺序 | number(越大越靠前) |
position | 以左上角为原点精准定位 | {x, y} 支持像素和百分比 |
10.3 Grid 网格属性
| 属性 | 作用 | 示例 |
|---|---|---|
columnsTemplate | 定义列宽模板 | '1fr 1fr 1fr' |
rowsTemplate | 定义行高模板 | '1fr 1fr' |
columnsGap | 列间距 | number |
rowsGap | 行间距 | number |
columnStart / columnEnd | GridItem 跨列 | number(从 1 开始) |
rowStart / rowEnd | GridItem 跨行 | number(从 1 开始) |
十一、常见布局陷阱与解决方案
11.1 flexGrow 不生效
原因:容器没有设置主轴的明确尺寸,或容器尺寸刚好等于子项内容尺寸
解决:确保容器有明确主轴尺寸(width/height),或使用 layoutWeight
11.2 子项溢出容器
原因:flexShrink 默认是 1,但如果所有子项 shrink 都是 0,则不会缩小
解决:给需要压缩的子项设置 flexShrink(1)
11.3 Wrap 不换行
原因:flexWrap 默认为 NoWrap
解决:显式设置 .flexWrap(FlexWrap.Wrap)
11.4 Stack 中子组件对齐方向混淆
误区:以为 Stack(TopStart) 中的子组件一定在左上角
正解:alignSelf 可以突破整体对齐。alignSelf(End) 会让子组件到右下角
记忆法:alignContent = 整体对齐,alignSelf = 个体突破
11.5 ColumnReverse 下 justifyContent 方向
误区:以为 Start 仍然是「顶部」
正解:ColumnReverse 下 Start = 底部,End = 顶部
记忆法:Start 永远指向主轴的「起始方向」
十二、性能优化建议
12.1 避免深层嵌套
Flex/Stack/Grid 容器可以嵌套,但建议深度控制在 3-4 层以内。过深的布局树会让 ArkUI 的布局引擎在每次状态变化时产生更多计算开销。
12.2 合理使用 layoutWeight
在卡片列表中使用 layoutWeight 比逐个计算百分比更高效,因为其分配算法在框架层是高度优化的。
12.3 @State 作用域最小化
@State 的变化会触发所在组件的 build() 重渲染,尽量将状态作用域限制在真正需要更新的层级。
12.4 懒加载长列表
当 Grid 或 Flex 中的子项超过 20 项时,考虑使用 LazyForEach 替代 ForEach 实现按需渲染:
LazyForEach(this.dataSource, (item) => {
GridItem() { ProductCard(item) }
})
12.5 阴影的性能成本
过多的 shadow 会影响滚动性能。建议对长列表卡片组使用较轻柔的阴影(color: '#10000000'),或仅对焦点卡片应用阴影。
十三、设计理念总结
回顾本文涉及的 12 种布局模式,可以归纳出鸿蒙 ArkUI 弹性布局的三条核心设计哲学:
1. 永远不用固定尺寸
能用 flexGrow、layoutWeight、flexBasis 的地方,就不要写 width(100) 或 height(200)。弹性布局的本质是让空间分配自适应,而非硬编码。
2. 拥抱「剩余空间」思维
弹性布局的核心是对容器「剩余空间」的分配。flexGrow 分配剩余空间,layoutWeight 重算全部空间,flexBasis 定义初始起点。理解这三个概念,弹性布局就不再是魔法。
3. 选对容器,事半功倍
| 需求 | 推荐容器 |
|---|---|
| 一维排列(水平/垂直) | Flex + flexDirection |
| 一维换行 | Flex + flexWrap(Wrap) |
| 层叠覆盖 | Stack |
| 二维表格/网格 | Grid |
| 简单垂直排列 | Column(Flex 的语法糖) |
| 简单水平排列 | Row(Flex 的语法糖) |
附录:项目文件结构
MyApplication/
├── AppScope/
│ ├── app.json5
│ └── resources/
├── entry/
│ └── src/main/ets/
│ ├── entryability/
│ │ └── EntryAbility.ets # 应用入口
│ └── pages/
│ ├── Index.ets # Column + justifyContent 演示
│ ├── GridFixedColDemo.ets # Grid 固定列网格演示
│ └── RunnerPage.ets # 跑酷游戏页
├── build-profile.json5 # 构建配置(SDK 24)
└── hvigorfile.ts # 构建脚本
项目构建配置指定了 targetSdkVersion: "6.1.1(24)",所有代码均在该 SDK 版本下编译通过。
结语
鸿蒙原生 ArkTS 的弹性布局体系——从 Flex 的四种方向、弹性伸缩、换行流式排列,到 Stack 的九种对齐、ZIndex 层叠控制,再到 Grid 的网格模板与跨列——为开发者提供了一套完备、高效、声明式的 UI 布局方案。
掌握这些布局模式后,你会发现:布局不再是与屏幕尺寸的博弈,而是对空间优雅的分配。 在多设备、多尺寸的鸿蒙生态中,弹性布局是你构建优秀用户体验的基石。

1181

被折叠的 条评论
为什么被折叠?



