HarmonyOS 7存量 2D 应用的渐进式空间化改造路线图
手上有一个跑了几年、几百万用户的 2D 应用,现在想蹭上空间计算。直接重做一版肯定是下策——产品逻辑、埋点、灰度策略全要重来,风险高到没人敢拍板。更现实的做法是分四步走,每一步都能独立上线、独立回滚,前一步为后一步铺路。
下面这套路线从最轻的"分层"开始,到最重的"沉浸化"结束。每一阶段都给判定标准和可量化指标,避免"感觉做得差不多了"这种模糊结论。
阶段划分与演进逻辑
改造的目标不是"变成 3D",而是让信息组织从平铺走向纵深。四阶段的划分依据是引入的维度数量:
- 阶段一:信息平铺(0 维变化,只做梳理)
- 阶段二:分层(引入 Z 的排序语义,但仍是 2D 渲染)
- 阶段三:3D 化(引入真实透视与旋转)
- 阶段四:沉浸化(引入光照、声音、手势等多通道协同)
每一阶段都建立在前一阶段稳定运行的基础上。跳过阶段二直接做阶段三,通常会出现"东西都转了,但主次还是乱的"。
阶段一:信息平铺怎么梳理
这一阶段不动渲染,只做信息架构的重新梳理。目标是把当前页面里所有元素按"主任务 / 上下文 / 环境"三类归档,为后面的分层做准备。
具体动作:盘点当前页面的所有信息块,给每一块打上优先级标签;识别哪些信息是"同时在线"的(可分层共存),哪些是"串行"的(需要跳转)。
判定标准:能画出一张信息分类表,每个元素都有明确归属,没有"说不清放哪类"的元素。
可量化指标:
| 指标 | 目标 |
|---|---|
| 信息块分类覆盖率 | 100%(无未归类元素) |
| 主任务识别一致性 | 3 名以上设计师独立分类,主任务结论一致 |
| 串行信息识别 | 明确标出所有必须跳转的场景 |
阶段二:分层改造怎么落地
这一阶段开始用Stack把归档好的信息叠起来。注意,这里只用位移和zIndex,不引入透视。目的很纯粹:验证"分层"这个信息结构用户能否理解。
做法上,主任务放到中心且zIndex最高并略作放大,上下文层降低不透明度并轻微偏移,环境层淡出。此时还是纯 2D 渲染,性能开销几乎为零。
判定标准:用户能在不看说明的情况下,判断出哪个是主任务。
可量化指标:
| 指标 | 目标 |
|---|---|
| 主任务首屏可见率 | ≥ 95% 的用户在 2 秒内指出主任务 |
| 主次视觉对比度 | 前景与背景层不透明度差 ≥ 0.25 |
| 误点率 | 上下文层误点率 ≤ 3% |
| 首帧渲染耗时 | 相较改造前增幅 ≤ 5% |
阶段三:3D 化怎么引入
到这一步才第一次出现真实的透视和旋转。把阶段二的层间位移改造成带perspective的纵深,让元素拥有真实的近大远小和遮挡。
这里的关键是统一透视值。所有层级用同一个perspective,否则纵深关系会失真,用户判断不了远近。
判定标准:关闭动画后截屏,用户能从静态画面里读出院落式的纵深层次(而不是只看到大小不同的平面卡片)。
可量化指标:
| 指标 | 目标 |
|---|---|
| 渲染帧率 | 稳定 ≥ 60fps(复杂页 ≥ 30fps) |
| 单帧 GPU 耗时 | 控制在预算内(如 < 8ms) |
| 透视一致性 | 同屏perspective值唯一 |
| 眩晕反馈 | 症状问卷(SSQ)得分不高于改造前基线 |
| 大角度倾斜占比 | 旋转角度 > 15 度的元素占比 < 10% |
阶段四:沉浸化怎么收口
最后一个阶段引入光照、空间音频、手势/传感器等多通道协同,让页面从"有纵深"走向"可进入"。
这一步对体验收益最大,风险也最大。光照方向不统一、声音方位和元素对不上、手势识别失败静默处理,任何一条都会让前面的努力白费。
判定标准:多通道反馈之间不打架——视觉、听觉、触觉表达的是同一件事。
可量化指标:
| 指标 | 目标 |
|---|---|
| 手势识别成功率 | ≥ 92% |
| 多通道一致性 | 声音方位与元素位置偏差 < 15 度 |
| 任务完成时间 | 相较阶段二不增加(理想情况下降 ≥ 10%) |
| 静音场景可用性 | 关闭声音后核心任务仍可 100% 完成 |
| 退出率 | 沉浸页退出率不高于平面页基线 |
渐进式改造的代码骨架
同一套组件,用stage变量控制它在各阶段的表现。这样灰度发布时,只需下发给不同用户不同的stage值。
@Entry@Componentstruct ProgressiveSpatialDemo{// 1=平铺 2=分层 3=3D化 4=沉浸化@Statestage:number=2;// 统一透视视距,阶段三及以后生效privatereadonlyPERSPECTIVE:number=1000;@BuilderLayerCard(title:string,role:'focus'|'context'|'env'){Column(){Row().width('100%').height(60).backgroundColor('#DCE6F2').borderRadius(10)Text(title).fontSize(14).margin({top:6})}.width(role==='focus'?180:140).padding(10).backgroundColor(Color.White).borderRadius(14)// 阶段二起:分层;阶段三起叠加纵深与透视.translate({x:role==='focus'?0:(role==='context'?120:-120),y:0,// 只有阶段三及以后才给 z 真实位移z:this.stage>=3?(role==='focus'?40:-80):0}).rotate({x:0,y:1,// 阶段三起才有旋转;阶段四允许更大角度angle:this.stage>=4?(role==='focus'?0:14):(this.stage>=3?(role==='focus'?0:8):0),perspective:this.PERSPECTIVE}).scale({x:role==='focus'&&this.stage>=2?1.1:1,y:role==='focus'&&this.stage>=2?1.1:1}).opacity(this.stage>=2?(role==='env'?0.5:(role==='context'?0.85:1)):1).zIndex(role==='focus'?3:(role==='context'?2:1))}build(){Column(){Stack({alignContent:Alignment.Center}){this.LayerCard('环境/推荐','env')this.LayerCard('上下文/相关','context')this.LayerCard('主任务','focus')}.width('100%').height(360)Row({space:8}){ForEach([1,2,3,4],(s:number)=>{Button(`阶段${s}`).backgroundColor(this.stage===s?'#E85D3D':'#E0E0E0').fontColor(this.stage===s?Color.White:'#333').onClick(()=>{this.getUIContext()?.animateTo({duration:350,curve:Curve.EaseInOut},()=>{this.stage=s;});})},(s:number)=>s.toString())}.margin({top:24})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}把stage从 1 拖到 4,能直观看到同一套结构如何从平铺长成有纵深的层次。工程上,这意味着一份代码同时支持四个阶段,灰度切换成本极低。
案例推演:设置中心的四阶段改造
拿设置中心做完整推演。假设当前是一个纵向列表,共 6 个一级入口、每项下有若干二级设置。
阶段一(信息平铺):盘点发现"账号与安全""网络与连接"是高频主任务,“关于本机”"隐私政策"是低频环境信息,其余为上下文。归档成三类。
阶段二(分层):主任务卡片居中并放大,上下文项半透明排布在周围,环境项弱化到边缘。此时用户一眼能判断"从哪开始"。
阶段三(3D 化):主任务卡片沿 Z 轴前移并轻微上倾,上下文卡片后退并绕 Y 轴内收,形成一条通往"设置深处"的走廊感。二级设置展开时不再是新页面,而是从主卡片后方推入。
阶段四(沉浸化):进入某项设置时,从元素对应方位播放一声轻微的空间提示音(AudioSpatializationManager可查询设备是否支持空间音频渲染);手势后推作为返回;主光源统一从左上打来,选中项高光增强。
每个阶段的回退路径都要提前设计好。空间化改造最容易犯的错是"一步到位",结果指标不达标时不知道退回哪一步。
几条小经验
- 先从信息架构开始,别从渲染开始。分层是 3D 的前提。
- 每阶段独立灰度。
stage变量是成本最低的灰度开关。 - 指标要可测。用 SSQ 量眩晕、用埋点量误点率,别靠主观感受拍板。
- 阶段三务必统一透视。这一步的坑最多,也最影响后续。
- 阶段四的声音和手势是"锦上添花",必须保证关掉它们核心任务照样能完成。
容易出问题的地方
- 跳过分层直接 3D 化。动效很炫,但主次混乱,用户依然不知道看哪。
- 把阶段当成一次性冲刺。四个阶段各自可能都需要一轮用户验证,急不得。
- 指标只测技术栈。帧率达标不代表体验达标,眩晕和误点率同样要看。
- 回退路径缺失。没有回退设计,出问题时只能整体下线,损失前面的成果。
- 忽略老设备。空间化对 GPU 有要求,灰度时要按设备能力分层下发,别一刀切。
#鸿蒙 #HarmonyOS 7(API 26)