右下角那个甩不掉的圆按钮,到底是怎么贴上去的
你打开任何一个主流 App,购物车、写笔记、刷消息,几乎都能在屏幕右下角看到一个圆形的悬浮按钮,列表怎么滚它都纹丝不动地浮在那里。再看头像右上角那个小红点,未读数字一变它就跟着变。很多新手第一反应是:这是不是要用绝对定位算坐标,或者套一层复杂的浮层框架?
其实不用。在华为鸿蒙系统的 ArkUI 框架里,这两种效果背后是同一个容器,叫 Stack。今天用华为仓颉编程语言把它讲透,你会发现悬浮按钮和角标,本质上就是一行对齐设置加一点点偏移。
Stack 的核心规则:后来者居上
Stack 是一个堆叠容器。它和 Row、Column 最大的区别在于:Row 把子组件横着排,Column 竖着排,而 Stack 是把子组件一层一层叠在一起,像摞扑克牌。
它只有一条核心规则需要记住:子组件按照书写顺序依次入栈,后写的盖在先写的上面。也就是说,你在代码里越靠后写的组件,在屏幕上层级越高、越靠前显示。这就是悬浮按钮能浮在列表之上的根本原因,因为我们把它写在了列表后面。
先导入模块,后面所有示例都基于它:
import kit.ArkUI.*

九宫格对齐:alignContent 的 9 个位置
光会叠还不够,你得能决定每一层叠在哪个位置。Stack 用 alignContent 参数控制所有子组件的对齐方式,它的取值是一个 Alignment 枚举,正好对应一个九宫格:
Stack(alignContent: Alignment.BottomEnd) { // 子组件 }
九个值分别是 TopStart、Top、TopEnd、Start、Center、End、BottomStart、Bottom、BottomEnd。把屏幕想象成井字格:Start 是左、End 是右、Top 是上、Bottom 是下,组合起来就是四个角加四条边加正中心。alignContent 不写时默认是 Center,所有子组件都往中间对齐。
理解了这个九宫格,悬浮按钮和角标的定位思路一下就清晰了:悬浮按钮要在右下角,那就是 BottomEnd;红点角标要在右上角,那就是 TopEnd。

实战一:列表上的悬浮添加按钮
我们来做最常见的场景,一个可滚动的内容区,右下角浮一个加号按钮。做法是:把内容写在前面铺满底层,把按钮写在后面让它盖在上层,容器对齐设为 BottomEnd:
Stack(alignContent: Alignment.BottomEnd) { Scroll { Column { // 这里是你的列表内容 } } .width(100.percent) .height(100.percent) Button("+") .width(56) .height(56) .borderRadius(28) .offset(x: -16, y: -16) } .width(100.percent) .height(100.percent)
注意按钮写在 Scroll 后面,所以它浮在内容之上。alignContent 把它推到右下角,最后用 offset 往左上各收一点,让它和屏幕边缘留出舒服的间距。这就是一个标准的浮动操作按钮。

实战二:头像右上角的红点角标
角标的思路和悬浮按钮一模一样,只是换个角落。把头像或图标写在前面当底,把红点写在后面盖上去,容器对齐设为 TopEnd:
Stack(alignContent: Alignment.TopEnd) { Image(@r(app.media.avatar)) .width(48) .height(48) Text("9") .fontSize(10) .fontColor(Color.WHITE) .backgroundColor(Color.RED) .width(16) .height(16) .borderRadius(8) .textAlign(TextAlign.Center) .offset(x: 4, y: -4) } .width(48) .height(48)
红点是一个带圆角背景的 Text,borderRadius 设成宽高的一半就变成了正圆。它写在 Image 后面所以浮在头像上层,TopEnd 把它推到右上角。这里的容器尺寸跟着头像走,红点就牢牢咬在头像的右上角。

offset 微调:让角标精确咬住边缘
你可能注意到了,光靠 alignContent 把组件推到角落还不够精细,红点往往需要稍微探出头像边缘一点点才好看。这一步靠 offset 完成。
offset 设置的是组件相对自身原始位置的偏移量,签名是 `offset(x: ?Length, y: ?Length)`。x 为正向右、为负向左,y 为正向下、为负向上。上面角标里的 `offset(x: 4, y: -4)`,意思就是在右上角的基础上,再往右挪 4、往上挪 4,让红点微微探出头像的右上角,视觉上更贴合真实 App。
如果你需要更强的控制,还有两个搭档:position 是相对父容器的绝对定位,markAnchor 用来改变组件自身的定位锚点。日常做角标和悬浮按钮,offset 配 alignContent 已经足够。
一个容易混淆的细节:alignContent 和 align 的冲突
最后提醒一个细节。Stack 的 alignContent 是容器级的对齐,而通用属性里还有一个 align,作用看起来相似。文档明确说明:当这两者同时设置时,后设置的那个生效。
所以如果你既在 Stack 上写了 alignContent,又在某个地方追加了 align,结果可能和预期不符。建议的做法是:统一用 alignContent 控制整体对齐,单个子组件的精细位置交给 offset,不要把两套对齐机制混在一起,省得排查布局错位。
什么时候该用 Stack
总结一下选型:当你需要让组件在空间上重叠时,就用 Stack。最典型的就是今天的两个场景,浮在内容上的操作按钮,和贴在图标角上的提示标记。除此之外,给卡片叠加渐变蒙层、给图片压一层文字说明、做加载时的半透明遮罩,都是 Stack 的主场。
记住三件事就够了:后写的盖在上面、alignContent 决定叠在哪个角、offset 做最后的微调。把这三点串起来,你已经能用华为仓颉编程语言在华为鸿蒙系统上做出大部分层叠界面了。