【共创稿事节】 HarmonyOS 7 空间化 UI 实战:从平面布局到空间层级的界面重构
很多页面看起来“不丑”,但就是没重点。按钮、卡片、图片、文字全部老老实实铺在一个平面上,用户第一眼看到的不是重点,而是一堆同时抢注意力的信息。HarmonyOS 7 把“空间化”进一步带到应用设计里之后,我更愿意把它理解成一次界面组织方式的变化:不是单纯把卡片做得更立体,而是重新安排内容的前后关系,让重要的信息自然往前走,不重要的信息适当往后退。
1. 为什么传统平面 UI 开始不够用了
先说一个很常见的页面。
假设我们做的是一个“设备控制中心”:顶部是欢迎信息,中间是一张设备状态卡片,下面有灯光、空调、门锁、场景模式等快捷入口,最底下还有最近操作记录。
功能其实一点都不少,布局也没什么明显问题。用 Column、Row、Grid 把这些内容排整齐,再配上圆角、背景色和一点阴影,页面很快就能做出来。
问题是,整齐不等于层级清楚。
当设备状态卡片、快捷入口、历史记录都处在近似的视觉平面上时,用户打开页面以后,需要自己判断:
- 哪一块是当前最重要的信息?
- 哪一块可以操作?
- 哪一块只是辅助说明?
- 我点开某张卡片以后,页面的注意力应该落在哪里?
这类问题在简单页面里不明显,一旦页面信息量上来,就很容易出现一种感觉:所有东西都在,但所有东西都差不多重要。
说白了,这就像把一屋子的东西全部摊在地板上。你确实一眼都能看到,可要找钥匙的时候,反而不一定快。

传统平面 UI 常见的问题大概可以归成三类。
1.1 信息主次靠颜色和字号硬撑
以前我们最常用的办法是:
- 标题大一点;
- 主卡片颜色深一点;
- 重要按钮换成高饱和色;
- 不重要的文字改成灰色。
这些方法当然有效,但它们基本都在同一个二维平面里解决问题。页面越复杂,需要叠加的视觉规则越多,最后反而可能变得很吵。
1.2 操作状态缺少“位置变化”
比如用户点开一张卡片,我们可能只是弹出一个 Dialog,或者直接跳转新页面。
从功能上没问题,但用户对“我刚刚操作的对象”和“新内容从哪里来的”这层关系,主要靠记忆去补。
如果界面能让主卡片向前强调、背景内容适当后退,用户会更容易理解当前状态。
1.3 动效很多,但动效之间没关系
还有一种更常见:为了让页面高级一点,到处加 scale、渐隐、弹跳、位移。
结果每个组件都挺忙,整个页面却没有统一逻辑。
所以真正的问题不是“动画不够多”,而是缺少一套空间层级规则。
2. 空间化 UI,不等于给卡片加个阴影
HarmonyOS 7 官方对空间化方向的描述很直接:从平面到立体,让沉浸空间为用户所见所感。
但这里特别容易产生一个误区:看到“立体”,马上想到 3D 旋转、透视、复杂光效。
其实对绝大多数普通应用来说,没必要一上来就做真正的三维场景。
我更愿意把移动端里的空间化 UI 拆成四件事:
- 信息有前后关系;
- 不同层承担不同职责;
- 交互发生时,视觉焦点会迁移;
- 动效服务于层级变化,而不是为了炫。
也就是说,空间化 UI 首先是一个信息架构问题,其次才是视觉效果问题。
HarmonyOS 7 在设计侧进一步强调沉浸光感、材质、空间属性和交互响应;在开发侧,我们仍然可以使用 ArkUI 熟悉的布局、图形变换和动画能力,把这种“前后关系”做出来。
这反而是好事。
因为开发者不需要把整个页面推倒重来,也不需要为了“空间化”就引入一套完全不同的开发模式。很多现有页面,本质上都是可以渐进式改造的。
3. 先别写代码:把页面拆成五个层级
这次我以一个“智能设备控制中心”页面为例。
原来的页面结构大概是:
Column
├── Header
├── DeviceStatusCard
├── QuickActions
├── SceneCards
└── HistoryList
从代码树看没问题,但从视觉关系看,它们几乎都是并列的。
我会先把它重新理解成五个空间层:
L0 背景层
L1 基础内容层
L2 核心信息层
L3 当前交互层
L4 反馈层
L0:背景层
背景层负责建立整体氛围。
它不应该抢内容,不应该放太多高对比元素。可以是纯色、渐变、弱化后的大图,也可以结合 HarmonyOS 7 的材质和沉浸光感设计。
重点只有一句话:它是舞台,不是演员。
L1:基础内容层
这里放页面里“需要存在,但当前不是最重要”的信息,比如历史记录、次级状态、辅助入口。
当用户进入某个核心操作时,这一层应该允许被适当弱化,例如降低一点透明度、轻微缩小或者向后退。
L2:核心信息层
比如当前设备状态卡片、主要任务卡片、主视觉内容。
这是用户进入页面后最应该先看到的东西。
它和基础内容层不能只靠“字号大 4px”来区分,而应该在尺寸、位置、留白、阴影、材质和交互响应上形成完整差异。
L3:当前交互层
当用户点击设备卡片以后,操作面板、调节面板或者展开内容应该进入这一层。
此时页面不是简单“多出来一个弹窗”,而是发生了一次空间关系调整:
当前对象往前,非当前内容往后。
L4:反馈层
Toast、状态提示、短时反馈、操作结果都属于这一层。
它的特点是层级最高,但停留时间最短。


这个拆法有一个很大的好处:后面做动画的时候,不需要每次临时想“这个组件怎么动比较酷”。
先看它属于哪一层,再决定它应该前移、后退、放大、缩小还是淡出,逻辑会顺很多。
4. 用 ArkUI 把“层级关系”真正写出来
页面结构确定以后,代码实现反而不复杂。
这类需要前后叠放的页面,我通常会先用 Stack 搭出整体结构,再在内部使用 Column、Row 等常规布局完成每一层自己的排版。
下面给一个简化版骨架:
@Entry
@Component
struct SpatialDashboard {
@State detailOpened: boolean = false
build() {
Stack({ alignContent: Alignment.Center }) {
// L0:背景层
Column()
.width('100%')
.height('100%')
.backgroundColor('#F4F6FA')
// L1:基础内容层
Column() {
this.Header()
this.HistoryArea()
}
.width('100%')
.height('100%')
.padding(20)
.opacity(this.detailOpened ? 0.72 : 1)
.scale({
x: this.detailOpened ? 0.97 : 1,
y: this.detailOpened ? 0.97 : 1
})
.translate({
y: this.detailOpened ? 12 : 0
})
// L2:核心信息层
this.DeviceCard()
// L3:当前交互层
if (this.detailOpened) {
this.ControlPanel()
}
}
.width('100%')
.height('100%')
}
}
这段代码里最重要的其实不是 Stack 本身,而是下面三个属性:
.opacity(...)
.scale(...)
.translate(...)
它们组合起来以后,就能非常直观地表达“退后”和“向前”。
比如进入详情状态时,基础内容层:
- 透明度略降;
- 尺寸缩小一点;
- 位置向下移动一点。
视觉上用户会自然感觉:这个区域不是消失了,只是暂时退到了后面。
这和直接 visibility(false) 的体验完全不一样。
4.1 为什么优先用 scale / translate,而不是频繁改 width / position
这里有一个很实际的性能点。
ArkUI 官方的动画优化指南明确提到:如果通过 width、height、position 等布局属性持续改变组件尺寸和位置,系统需要重新计算布局;而 scale、translate 这类图形变换是在布局结果之上做显示变换,通常可以减少不必要的重新布局。
所以类似“卡片轻微前移”“背景退后”“内容缩放”这类空间化动画,能用图形变换解决时,我会优先考虑图形变换。
不是因为代码短,而是因为这类效果本来就属于“显示状态变化”,没必要每一帧都把整个布局重新算一遍。
5. 把主卡片真正“推到前面”
核心卡片可以再单独做一次状态变化。
例如:
@Builder
DeviceCard() {
Column() {
Text('客厅设备')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('4 个设备在线 · 空气质量良好')
.fontSize(14)
.opacity(0.65)
Row() {
Button('打开控制')
.onClick(() => {
this.getUIContext().animateTo({
duration: 240,
curve: Curve.EaseOut
}, () => {
this.detailOpened = true
})
})
}
.margin({ top: 20 })
}
.width('86%')
.padding(24)
.borderRadius(28)
.backgroundColor('#FFFFFF')
.scale({
x: this.detailOpened ? 1.03 : 1,
y: this.detailOpened ? 1.03 : 1
})
.translate({
y: this.detailOpened ? -42 : 0
})
.shadow({
radius: this.detailOpened ? 28 : 12,
color: '#22000000',
offsetX: 0,
offsetY: this.detailOpened ? 12 : 5
})
}
点击以后,卡片会轻微放大、上移,同时阴影范围增加。
注意我这里故意用了“轻微”。
空间化 UI 最怕的就是所有变化都用力过猛。
scale 从 1 到 1.03,用户能感觉到它往前走了,但不会出现“卡片突然扑到脸上”的感觉。
translate 也不需要几十上百像素乱飞,只要能把视觉焦点从背景里拉出来就够了。

6. 真正的改造重点:不是效果变多,而是信息重新排队
如果把改造前后的页面放在一起看,会发现真正明显的变化其实不是“多了几个动画”。
改造前:
标题
卡片
按钮
卡片
列表
按钮
列表
用户自己找重点。
改造后:
背景
↓
基础信息
↓
核心卡片
↓
当前操作
↓
即时反馈
系统开始主动告诉用户什么更重要。
这就是我理解的空间层级价值。

而且这种思路很适合逐步改造旧项目。
你完全没必要第一天就把整个 App 做成“空间世界”。
先找最关键的 1~2 个页面:
- 首页;
- 详情页;
- 播放页;
- 控制中心;
- 数据仪表盘;
- 商品展示页。
把用户最关注的核心对象提出来,把背景信息退下去,先把前后关系做对,效果通常就已经很明显。
7. 交互不是越炫越好,空间感也要有“刹车”
做到这里,最容易开始上头。
主卡片能放大,那旁边卡片是不是也旋转一下?
页面能后退,那背景是不是再加一层模糊?
按钮能跟随焦点,那是不是再加点弹簧动画?
我的建议是:先忍住。
空间化 UI 的目的不是证明开发者会多少种动画,而是让页面更容易理解。
我一般会用三个标准判断一个动效该不该留。
7.1 它有没有告诉用户“发生了什么”
比如主卡片上移、背景退后,这个动画表达的是“当前操作对象被提到前面”。
有明确语义,可以留。
如果只是因为页面看起来有点空,所以让按钮左右晃一下,那就没什么必要。
7.2 它有没有建立连续关系
用户点的是 A,接下来出现的是 A 的控制面板,那么动画应该让用户感觉这两个东西是连续的。
如果 A 在左边消失,控制面板突然从右边飞进来,虽然热闹,但关系反而断了。
7.3 它会不会让用户等
动画再高级,只要让用户产生“你倒是快点”的感觉,就过头了。
普通点击反馈、卡片聚焦、面板展开,我会更倾向于短时长、快响应。空间感靠层级变化来建立,不靠拖时间建立。

8. 一个很容易忽略的坑:层级多了,点击区域也可能乱
空间化页面里经常会出现叠层。
看起来是下面一张卡片,实际上上面可能还压着一个透明组件。
结果就是:
用户看得到按钮,却点不到。
这类问题光看代码有时候不容易找。
DevEco Studio 的 ArkUI Inspector 在这里很实用。除了看组件树、属性、状态变量和边框,现在还支持按组件粒度做 3D 展开应用。
换句话说,可以把页面组件像“分层模型”一样展开,看谁压在谁上面。
这对空间化页面尤其合适。
因为我们本身就在强调层级,最终当然也应该从层级角度检查:
- 是否有不必要的透明遮挡;
- 交互层是不是压住了基础层;
- 某些组件是不是层层嵌套得过深;
- 页面关闭详情以后,临时交互层有没有真正下树;
- 点击区域和视觉区域是否一致。
这比只盯着模拟器截图靠谱很多。
9. DevEco Studio 里我会怎么验证这个页面
做完页面以后,我一般不会只说一句“跑起来没报错”就算结束。
至少会从下面五个角度再看一次。
9.1 第一眼焦点是不是正确
启动页面以后,不操作。
问自己一个很简单的问题:
三秒以内,我最先看到的是不是核心卡片?
如果答案不是,那空间层级基本还没有建立起来。
9.2 聚焦以后,背景有没有退得太狠
背景退得太少,焦点不明显。
退得太多,用户又会觉得页面突然换了一套界面。
好的状态应该是用户仍然知道“我还在原来的页面里”,只是当前操作对象更靠前。
9.3 动画是否连续
点击卡片、展开面板、关闭面板,这三个状态要来回跑几次。
尤其关注反向动画。
很多页面打开的时候很好看,一关闭就瞬间跳回原位,这种割裂感非常明显。
9.4 连续操作时是否掉帧
不要只点一次。
快速打开、关闭,多操作几轮,再观察动画是否稳定。
官方的动画性能指南也建议合理选择系统提供的属性动画、显式动画和图形变换能力,避免不必要的 UI 主线程负载。
9.5 用 ArkUI Inspector 看实际组件层次
最后再切到 Inspector。
这一步能把很多“肉眼看起来正常”的结构问题揪出来。
尤其是做了多个 Stack、浮层、透明层以后,3D 展开非常直观。
10. 空间化设计不是所有页面都必须做
讲到这里还得泼一点冷水。
不是每个页面都适合做空间化。
比如:
- 登录页;
- 简单设置页;
- 单纯表单页;
- 只有两三个选项的确认页;
- 强调高效率输入的工具页面。
这些页面的核心目标是“赶紧完成任务”。
如果为了空间感加入过多层级、材质和动效,反而会降低效率。
真正适合空间化的,通常是这些场景:
内容有明确主次
比如媒体播放器、商品详情、设备控制、数据看板。
用户会围绕一个对象持续操作
例如照片、视频、设备、商品、任务卡片。
页面状态之间有明显上下文关系
用户需要知道“我从哪来、现在在操作谁、完成以后回到哪里”。
这种场景里,空间层级不仅是视觉效果,它实际上能帮助用户理解产品结构。
11. 从“平面布局”改到“空间层级”,我最大的感受
以前做页面,我们很容易把注意力放在尺寸上:
“这里 16vp。”
“那里圆角 24vp。”
“这个按钮往下挪 8vp。”
这些当然重要。
但空间化 UI 会迫使我们多问一个问题:
这个元素在用户当前任务里,到底应该站在前面还是后面?
一旦把这个问题想清楚,很多设计决定反而会更容易。
重要的信息不用再拼命加颜色,因为它可以通过位置和层级获得注意力。
次要信息也不用彻底隐藏,因为它可以自然退后。
交互状态不用每次都打开新页面,因为当前对象可以在原页面里被“提到前面”。
这其实是一种很朴素的设计逻辑。
就像现实生活里,我们拿起一本书的时候,书会离眼睛更近,桌面上的其他东西自然变成背景。我们不需要有人告诉我们“现在请重点关注这本书”,空间关系本身已经把信息说清楚了。
HarmonyOS 7 把空间感、沉浸光感和更丰富的交互表达继续往前推进,对应用开发者来说,真正值得关注的并不是“以后是不是所有页面都要做成 3D”。
而是:
我们终于可以少依赖一点颜色、边框和字号,开始用空间关系本身组织信息。

12. 最后总结
回头看这次改造,其实没有什么特别玄学的东西。
核心就六步:
- 找到原平面页面的问题;
- 重新梳理信息优先级;
- 把页面拆成背景、基础内容、核心内容、当前交互和反馈几个层级;
- 用
Stack建立叠层关系; - 用
scale、translate、opacity和animateTo表达前后变化; - 最后在 DevEco Studio 和 ArkUI Inspector 里验证布局、遮挡、交互与动画性能。
真正要避免的反而是“为了空间化而空间化”。
如果一个阴影能解决问题,就没必要旋转。
如果一次轻微缩放能建立焦点,就没必要让整张卡片飞来飞去。
空间化 UI 的重点,不是把界面做得更花,而是让用户更快看懂主次关系。
这也是我觉得 HarmonyOS 7 空间化设计最值得开发者认真研究的一点。
参考资料
-
华为开发者联盟:HarmonyOS 7 新能力一览
https://developer.huawei.com/consumer/cn/features/ -
华为开发者联盟:HarmonyOS 设计规范和指南
https://developer.huawei.com/consumer/cn/design -
华为开发者文档:优化动画性能
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-animation-usage-guide -
华为开发者文档:ArkUI Inspector 布局分析
https://developer.huawei.com/consumer/cn/doc/doccenter-deveco-studio/ide-arkui-inspector -
华为开发者联盟:HarmonyOS 应用开发工具与平台
https://developer.huawei.com/consumer/cn/develop/index.html
更多推荐




所有评论(0)