【共创季稿事节】鸿蒙原生 ArkTS 布局方式入门:Stack 堆叠布局 — 层叠式排列的核心概念
鸿蒙原生 ArkTS 布局方式入门:Stack 堆叠布局 — 层叠式排列的核心概念



一、引言
在鸿蒙原生应用开发中,布局是 UI 最核心的能力。ArkUI 的 Column、Row、Flex、RelativeContainer 各有所长,而本文的主角 Stack(堆叠布局) 是其中唯一天然支持 Z 轴层叠 的容器。
Stack 在 Android 对应 FrameLayout,在 Flutter 对应 Stack,在 Web 对应 position: absolute + relative。它的核心思想极简:子组件按添加顺序,从下往上依次叠放——先添加的在底层(Z 值小),后添加的在上层(Z 值大)。
应用场景非常广泛:头像右上角叠加未读红点、商品图片左上角显示"热卖"标签、卡片底部叠加半透明遮罩、多个头像部分重叠形成群组、页面顶层覆盖加载动画屏蔽层。没有掌握 Stack,就不算真正掌握了鸿蒙 UI 开发。
二、Stack 布局核心概念
2.1 什么是 Stack
Stack 是 ArkUI 内置容器组件,无需 import,可直接使用。它让子组件在 Z 轴方向上层叠排列。与 Column(纵向)和 Row(横向)不同,Stack 的所有子组件占据同一平面空间,通过前后叠放构建 UI 层次。
| 布局容器 | 排列方向 | 生活类比 |
|---|---|---|
| Column | Y 轴(垂直) | 书架上的书,从上到下 |
| Row | X 轴(水平) | 餐桌上的餐具,从左到右 |
| Stack | Z 轴(深度) | 桌面上叠放的纸张 |
2.2 Z 轴层叠机制
Stack 的规则极其简单:先添加的在底层,后添加的在上层。
Z 轴方向(越往上越靠前)
↑
┌────────────────────┐ ← 第3层:Text(最上层)
│ Z=3(顶层) │
└────────────────────┘
┌────────────────────┐ ← 第2层:绿色矩形(中层)
│ Z=2(中层) │
└────────────────────┘
┌────────────────────┐ ← 第1层:蓝色矩形(底层)
│ Z=1(底层) │
└────────────────────┘
这个顺序不可逆——无法在运行时动态调整某个子项的 Z 轴顺序(除非重新排列代码中的添加顺序)。因此编码时建议按"底层 → 中层 → 顶层"顺序编写子组件。
2.3 API 24 的注意事项
- 对齐枚举统一为
Alignment:StackAlign已废弃,使用Alignment枚举 - 性能优化:子组件超过 10 个时布局计算性能提升约 30%
- 嵌套稳定性:多层 Stack 嵌套的尺寸溢出问题已修复
三、Stack 基本用法
3.1 最简单的 Stack
@Entry
@Component
struct SimpleStack {
build() {
Stack() {
// 子组件在此层叠
}
.width('100%')
.height('100%')
}
}
Stack 是 ArkUI 的全局内置类型,无需 import 声明。
3.2 alignContent 参数
构造函数接受可选的 alignContent,控制所有子组件的默认对齐方式:
Stack({ alignContent: Alignment.Center }) {
// 所有子组件默认居中对齐
}
不指定时默认值为 Alignment.Center。Alignment 共 9 个取值:
| 对齐值 | 说明 |
|---|---|
TopStart / Top / TopEnd |
左上 / 顶部居中 / 右上 |
Start / Center / End |
左中 / 居中 / 右中 |
BottomStart / Bottom / BottomEnd |
左下 / 底部居中 / 右下 |
3.3 尺寸行为要点
- 无子组件时 Stack 尺寸为 0×0
- 子组件全部固定尺寸时,Stack 自适应到最大子组件的尺寸
- 子组件使用百分比(如
width('100%'))时,Stack 必须有固定尺寸 - 最佳实践:始终为 Stack 显式设置
width和height
四、alignContent 动态切换
使用 @State 动态切换 9 种对齐方式,直观感受每种模式的效果:
@State currentAlignIndex: number = 0;
private alignOptions: Alignment[] = [
Alignment.TopStart, Alignment.Top, Alignment.TopEnd,
Alignment.Start, Alignment.Center, Alignment.End,
Alignment.BottomStart, Alignment.Bottom, Alignment.BottomEnd,
];
Stack({ alignContent: this.alignOptions[this.currentAlignIndex] }) {
Rect().fill('#22000000').width('100%').height('100%');
Rect().width(60).height(60).fill('#FFE74C3C');
Rect().width(50).height(50).fill('#FF3498DB');
Rect().width(40).height(40).fill('#FF2ECC71');
}
观察要点:TopStart 时三方块"吸"到左上角;Center 时叠在正中间;BottomEnd 时移向右下角。alignContent 是全局设置,同时影响所有子组件。如需单独控制某个子项,用 .position() 或 .margin()。
五、实战示例详解
5.1 Z 轴层叠顺序演示
三个不同颜色、尺寸的矩形从下往上叠放,直观展示 Z 轴层级:
Stack({ alignContent: Alignment.Center }) {
// 第1层(最底层):蓝色最大矩形
Rect().width(240).height(200).fill('#FF4A90D9')
.radiusWidth(12);
// 第2层(中层):绿色中等矩形
Rect().width(180).height(150).fill('#FF50C878')
.radiusWidth(12);
// 第3层(最顶层):白色文字
Text('Z=3 (最顶层)').fontSize(14).fontColor(Color.White);
}
.width(240).height(200);
效果:三层矩形层层嵌套,蓝色边缘露出约 30px,绿色露出约 15px。底层尺寸决定容器尺寸,中层和顶层只需关注自身尺寸。若三层尺寸相同则完全覆盖,需要用 opacity 才能看到下层。
5.2 角标/徽标叠加(Badge)
这是 Stack 最经典的应用——在图标右上角叠加红色未读数:
Stack({ alignContent: Alignment.TopStart }) {
// 底层:消息图标
Circle().width(80).height(80).fill('#FFEEEEEE')
.stroke('#FFCCCCCC').strokeWidth(2);
// 信封符号
Text('✉').fontSize(32).fontColor('#FF666666')
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
});
// 顶层:红色角标
Stack({ alignContent: Alignment.Center }) {
Circle().width(26).height(26).fill('#FFE74C3C');
Text('3').fontSize(12).fontColor(Color.White)
.fontWeight(FontWeight.Bold);
}
.position({ x: 58, y: -6 }); // ★ 绝对定位到右上角
}
.width(80).height(80);
原理:这是一个二级 Stack 嵌套。外层 Stack 为 TopStart 对齐,内层角标通过 .position({ x: 58, y: -6 }) 偏移到右上角。X 偏移 = 图标宽(80) - 角标宽(26) + 露出量(4) = 58。若需角标在左下角,将外层改为 BottomStart 并调整坐标即可。
5.3 头像堆叠排列(群组场景)
多个头像部分重叠形成群组效果,常用于"xxx 等 N 人赞了":
Stack({ alignContent: Alignment.Start }) {
// 头像 1 — 最左侧
Circle().width(48).height(48).fill('#FFE74C3C')
.stroke(Color.White).strokeWidth(3);
// 头像 2 — 右移 30px(重叠 18px)
Circle().width(48).height(48).fill('#FF3498DB')
.stroke(Color.White).strokeWidth(3).margin({ left: 30 });
// 头像 3 — 右移 60px
Circle().width(48).height(48).fill('#FF2ECC71')
.stroke(Color.White).strokeWidth(3).margin({ left: 60 });
// +N 提示
Circle().width(48).height(48).fill('#FF999999')
.stroke(Color.White).strokeWidth(3).margin({ left: 90 });
Text('+3').fontSize(14).fontColor(Color.White)
.fontWeight(FontWeight.Bold).margin({ left: 90 });
}
.width('100%').height(56).padding({ left: 10 });
技巧:使用 Alignment.Start 左对齐,通过递增的 .margin({ left: N }) 让每个头像逐步偏移。重叠量 18px(约头像宽度的 37.5%)在视觉上最舒适。实际项目中可用 ForEach 循环渲染并用 index * overlapOffset 计算偏移量。
5.4 卡片阴影叠加层
通过 Stack 叠加一个偏移的"阴影层",实现比 .shadow() 更丰富的视觉效果:
Stack({ alignContent: Alignment.Center }) {
// 阴影层:半透明黑色 + 向右下偏移
Rect().width(260).height(100).fill('#22000000')
.radiusWidth(12).translate({ x: 4, y: 4 });
// 主卡片:白色 + 系统阴影
Rect().width(260).height(100).fill(Color.White)
.radiusWidth(12)
.shadow({ radius: 8, color: '#33000000', offsetY: 4 });
// 卡片内容
Column({ space: 4 }) {
Text('卡片标题').fontSize(16).fontWeight(FontWeight.Bold);
Text('卡片正文内容,展示 Stack 布局的典型应用场景。')
.fontSize(13).fontColor('#FF888888');
}
.alignItems(HorizontalAlign.Start).padding({ left: 16, right: 16 });
}
.width(260).height(100);
两层阴影原理:底层半透明矩形用 translate 偏移 4px 模拟投影,上层主卡片用 shadow 提供柔和边缘阴影。调整 translate 方向即可控制阴影出现在右下、正下或左下。
5.5 加载遮罩层
页面加载时在内容上方显示遮罩 + 加载动画:
Stack() {
// 底层:页面内容
Column() { /* 列表、卡片等 */ }
.width('100%').height('100%');
// 顶层:遮罩 + 加载动画(通过状态变量控制显示)
if (this.isLoading) {
Column() {
LoadingProgress().width(40).height(40).color(Color.White);
Text('加载中...').fontSize(14).fontColor(Color.White)
.margin({ top: 12 });
}
.width('100%').height('100%')
.backgroundColor('#66000000') // 40% 透明度黑色遮罩
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center);
}
}
要点:用 if 条件渲染控制遮罩显示/隐藏;40% 透明度黑色既能屏蔽操作又能让下层隐约可见。
六、子组件定位方式对比
Stack 提供四种定位方式:
| 方式 | 作用域 | 适用场景 |
|---|---|---|
alignContent |
全局(所有子组件) | 统一对齐,如全部居中 |
.margin() |
单个子组件 | 头像堆叠等逐个偏移 |
.position() |
单个子组件 | 角标等精确定位 |
.alignRules() |
单个子组件 | 锚点对齐,类似 RelativeContainer |
七、最佳实践与避坑指南
7.1 适合 vs 不适合
✅ 适合:角标 / 头像堆叠 / 卡片阴影 / 加载遮罩 / 图片标签 / FAB 按钮 / 全屏加载动画
❌ 不适合:列表布局(用 List)/ 简单纵向排列(用 Column)/ 简单横向排列(用 Row)/ 自适应换行(用 FlexWrap)
7.2 常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
| 子组件显示不全 | Stack 尺寸太小 | 显式设置 width/height |
| 百分比尺寸无效 | Stack 无固定尺寸 | 给 Stack 设固定尺寸 |
| 角标位置不对 | 对齐方式不符预期 | 检查外层 alignContent |
| 子组件全不可见 | 尺寸均为 0 | 至少一个子组件设固定尺寸 |
| import Stack 报错 | 误以为需 import | Stack 是内置组件,无需 import |
7.3 性能建议
- 单个 Stack 子组件建议不超过 10 个
- 嵌套不超过 3 层
- 非永久显示的组件用
if条件渲染替代.visibility() - 优先用
.margin()而不是.position()
八、Stack 与其他布局对比
| 特性 | Stack | Column | Row | RelativeContainer |
|---|---|---|---|---|
| 排列方向 | Z 轴层叠 | Y 轴垂直 | X 轴水平 | 锚点相对 |
| 子组件重叠 | ✅ 是 | ❌ 否 | ❌ 否 | ✅ 是 |
| position 定位 | ✅ | ⚠️ 有限 | ⚠️ 有限 | ❌ 不支持 |
| alignRules | ✅ | ❌ | ❌ | ✅ 原生支持 |
| 层叠效果 | ✅ 最佳 | ❌ | ❌ | ⚠️ 可实现 |
选择建议:90% 场景用 Column + Row;需层叠用 Stack;需精细锚点用 RelativeContainer;需弹性布局用 Flex。
九、总结
本文从 Stack 布局的核心——Z 轴层叠机制出发,通过 5 个实战示例,全面讲解了 Stack 在鸿蒙原生 ArkTS 开发中的用法。
核心要点:
- Z 轴层叠:子组件按添加顺序从下往上叠放,先添加的在底层
- 对齐控制:
alignContent共 9 种取值(Alignment枚举),全局控制 - 定位方式:全局
alignContent、子级.margin()、子级.position()、锚点alignRules() - 实战场景:角标叠加、头像堆叠、阴影层、遮罩层——覆盖 90% 的 Stack 使用场景
- API 24:使用
Alignment枚举,Stack 为内置组件无需 import
Stack 是 ArkUI 布局体系中"四两拨千斤"的存在——语法极简,应用极广。掌握 Stack,你的鸿蒙应用 UI 表达能力将提升一个台阶。
更多推荐




所有评论(0)