【共创稿事节】空间化改造“贴地版”:从打开DevEco到跑通第一个Z轴卡片
第二集 本文为实战篇
第一集 战略篇:空间计算的“认知门槛”:从2D铺大饼到3D叠千层的设计范式转型
——鸿蒙7空间化设计不是玄学,是三条Z轴规则+五个实战步骤+一张自检表
受众
初级鸿蒙应用开发工程师、正在学ArkUI的新手、被产品经理或老板塞过来一句“给我们App加个空间化”的兄弟。你不需要懂设计理论,也不需要理解什么叫“空间范式”,照着这五个步骤抄就完事了。
场景锚定
你的Leader说“客户要空间感”,你的PM说“友商加了Z轴,我们也要”。你知道HarmonyOS 7(API 26)有沉浸光感组件,但打开DevEco后不知道第一行代码写在哪。这篇文章不跟你讲设计哲学,就给你五步可复制的操作步骤、三条死记硬背的参数规则,以及一张“做完打勾”的自检表。照着做,下班前能交差。
摘要
这是一篇零门槛、纯操作、不讲道理的空间化快速接入指南。与上一篇的姊妹篇不同——上一篇讲“战略层的判断框架(做不做、做多深)”,这篇只讲“战术层的照抄模板(怎么做)”。
你能从这篇拿到什么?
- 三条死记硬背的Z轴规则(不用理解为什么,直接用)
- 五步完成一个空间化卡片页面的操作流程(每一步都告诉你点哪里、写什么)
- 一个“3D查看”按钮的最小可编译代码块(直接复制粘贴改路径)
- 一张空间化改造完成度自检表(做完打勾交付)
前置条件: 已安装DevEco Studio 26.0.0.100或以上,已创建一个Stage模型空工程(API 26)。不需要HarmonyOS 7真机,模拟器即可。
正文
急诊入口(运行前先确认):
打开你的DevEco项目,检查以下三项全✓才能继续:
-
build.gradle中compileSdkVersion = 26 -
module.json5中有"requestPermissions"字段(空的也行) - 模拟器或真机已连接,
hdc list targets能刷出设备ID
任一未打勾→先补环境,本文不适用。
问: 我刚入职三个月,组长说“把首页的卡片做成有空间感的,今天下班前给我看看”。我连鸿蒙的空间化API有哪些都不知道。能给一个“不需要理解直接抄”的版本吗?
答:
可以。给你三条死记硬背的规则,不解释为什么,你照着敲就行。
规则一:Z轴分层最多三层
不要超过三个深度层级。浅层(靠近屏幕)、中层、深层,够用了。
使用场景速查(直接复制到Figma标注或代码注释):
- 页面背景 → 不设Z值(躺在最底下)
- 普通卡片/列表项 → Z=2
- 悬浮按钮/标签 → Z=1(比卡片更靠近用户)
- Dialog弹窗/底部面板 → Z=3(在最上面)
规则二:Z值与阴影的固定配比
Z值每增加1,Y偏移翻倍,模糊度=偏移量×2。
Z=1 → 偏移量4px + 模糊度8px + 不透明度20%
Z=2 → 偏移量8px + 模糊度16px + 不透明度25%
Z=3 → 偏移量12px + 模糊度24px + 不透明度30%
把这个表贴在显示器边上,做设计稿的时候直接查,不要自己调。
规则三:深色模式下的光感补偿
如果你用了沉浸光感组件,深色模式下环境光必须 ≥ 30% 亮度,否则黑色背景+低环境光 = 用户看不清任何东西。
这三条规则在代码里怎么体现?下一轮直接给你最小可编译代码块。
问: 收到三条规则。现在能不能直接给我一段代码,让我跑通一个“有空间感的卡片页面”?我要能看到效果,不然没法跟组长汇报。
答:
可以。下面是一段最小可编译代码,直接粘贴到 entry/src/main/ets/pages/Index.ets 替换原有内容。
// entry/src/main/ets/pages/Index.ets
// 最小空间化卡片页面 - 含Z轴分层+悬浮按钮
// 适用环境:HarmonyOS 7 (API 26) 模拟器或真机
import { router } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State cardList: string[] = ['商品A', '商品B', '商品C'];
build() {
Column() {
// 标题栏(Z=2层级 - 通过shadow模拟)
Text('空间化卡片示例')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 16, bottom: 8 })
.shadow({
radius: 16, // Z=2对应的模糊度
offsetX: 0,
offsetY: 8, // Z=2对应的偏移量
color: 'rgba(0,0,0,0.25)' // Z=2对应的不透明度25%
})
// 卡片列表(每个卡片Z=2层级)
List({ space: 12 }) {
ForEach(this.cardList, (item: string) => {
ListItem() {
Row() {
Text(item)
.fontSize(18)
Blank()
Text('查看详情')
.fontColor('#007AFF')
}
.width('100%')
.height(60)
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 16,
offsetX: 0,
offsetY: 8,
color: 'rgba(0,0,0,0.25)'
})
}
})
}
.width('100%')
.padding({ left: 16, right: 16 })
.layoutWeight(1)
// 底部悬浮按钮(Z=1层级 - 比卡片更靠近用户)
Button('加入购物车')
.width('90%')
.height(48)
.backgroundColor('#007AFF')
.fontColor(Color.White)
.borderRadius(24)
.shadow({
radius: 8, // Z=1对应的模糊度
offsetX: 0,
offsetY: 4, // Z=1对应的偏移量
color: 'rgba(0,122,255,0.20)' // Z=1对应的不透明度20%
})
.margin({ bottom: 24 })
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
效果说明:
- 标题栏和卡片列表:Z=2(阴影偏移8px,模糊16px)
- 底部按钮:Z=1(阴影偏移4px,模糊8px),比卡片更靠近用户
- 背景:#F5F5F5平铺在最底层
验证命令(确保生效):
打开模拟器,你应该看到:
- 每个卡片在背景上都有清晰的阴影
- 底部按钮的阴影比卡片更淡(因为Z=1)
- 卡片之间由浅色背景+阴影自然分隔,不需要边框
如果阴影太强或太弱,调整shadow里的color透明度。
问: 跑了你给的代码,卡片确实有阴影了。但组长说要“有3D感”,不是“有阴影”。接下来怎么做?比如在卡片里加一个可以旋转查看的商品模型?
答:
你组长的“3D感”需求,在鸿蒙上实现分三种难度:
| 难度 | 做法 | 你的情况 |
|---|---|---|
| 最简单 | 卡片加Z轴阴影+轻微旋转动效(5行代码) | ✅ 你已做到 |
| 中等 | 卡片内嵌入GaussianModelView(20行代码,渲染.gsplat模型) | ⬜ 下一步 |
| 最难 | 全屏沉浸式空间体验(需要3D模型+空间音频) | 不推荐新手 |
既然组长要“3D感”,给他中等方案。先确认你有没有.gsplat格式的3D模型文件:
- 有 → 继续往下读“嵌入3D模型”
- 没有 → 用HarmonyOS 7的Spatial Recon Kit(空间重建套件)把2D照片转成.gsplat(参考姊妹篇的方法),或用系统自带示例模型
嵌入3D模型(替换卡片内容):
在上面的卡片列表基础上,修改List item内容:
// 修改前(卡片内容为文字)
Row() {
Text(item).fontSize(18)
Blank()
Text('查看详情').fontColor('#007AFF')
}
// 修改后(卡片内容为3D模型预览)
import { GaussianModelView } from '@arkui.3D';
Column() {
// 3D模型缩略视图
GaussianModelView({
modelSource: '/data/app/demo.gsplat', // 替换为你的模型路径
autoRotate: true, // 自动旋转展示
scale: 0.5, // 缩略图尺寸
backgroundColor: 0xFFFFFF
})
.width('100%')
.height(160)
Row() {
Text(item).fontSize(16)
Blank()
Text('点击旋转查看')
.fontSize(12)
.fontColor('#007AFF')
}
.width('100%')
.padding({ top: 8 })
}
特别注意: modelSource路径必须是设备上已存在的.gsplat文件。如果你用模拟器测试,先把模型文件push进去:
hdc push ./demo.gsplat /data/app/demo.gsplat
完成以上步骤后的效果:
- 卡片有Z=2阴影
- 卡片内有一个自动旋转的3D模型
- 用户看到的是“卡片带着模型浮在背景上”——这就是组长要的“3D感”
问: 搞定了。组长看完点头了。但我还想做个“3D查看”按钮,点击后弹出一个全屏的3D模型查看器——这个怎么接?顺便问一句,我们团队可能有两三个产品都要用这个空间化方案,有没有通用封装的方法?
答:
两个问题拆开答。
问题1:全屏3D查看器(最小实现)
在点击卡片时,跳转到一个全屏的GaussianModelView页面。新建entry/src/main/ets/pages/ModelViewer.ets:
// entry/src/main/ets/pages/ModelViewer.ets
// 全屏3D查看器(可缩放/旋转/平移)
import { GaussianModelView } from '@arkui.3D';
import { router } from '@kit.ArkUI';
@Entry
@Component
struct ModelViewer {
@State modelPath: string = router.getParams()?.['modelPath'] || '/data/app/demo.gsplat';
build() {
Column() {
// 返回按钮(Z=1)
Row() {
Text('← 返回')
.fontSize(18)
.fontColor(Color.White)
.onClick(() => router.back())
Blank()
Text('空间查看器')
.fontSize(18)
.fontColor(Color.White)
Blank()
Text(' ')
}
.width('100%')
.height(50)
.padding(16)
.backgroundColor('rgba(0,0,0,0.5)')
.shadow({
radius: 8,
offsetY: 4,
color: 'rgba(0,0,0,0.20)'
})
// 全屏3D模型(可交互旋转)
GaussianModelView({
modelSource: this.modelPath,
autoRotate: false, // 全屏模式下让用户手动旋转
scale: 1.0,
backgroundColor: 0x1a1a2e
})
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor(0x1a1a2e)
}
}
然后在卡片列表的点击事件中跳转:
// 在卡片ListItem的onClick中添加
.onClick(() => {
router.pushUrl({
url: 'pages/ModelViewer',
params: { modelPath: '/data/app/demo.gsplat' }
});
})
问题2:通用封装建议(3-5个产品共用一套方案)
如果你的团队有3-5个鸿蒙应用都要做空间化,不建议每个应用单独写一遍。建议封装成以下结构:
/common-spatial
├── components/
│ ├── SpatialCard.ets // 带Z轴阴影的通用卡片组件(参数化:Z值、内容区、点击事件)
│ └── ModelViewerPage.ets // 全屏3D查看器页面(可独立跳转)
├── utils/
│ └── SpatialHelper.ets // 设备能力检测+降级判断(参考姊妹篇的降级策略)
└── types/
└── SpatialTypes.ets // Z轴层级枚举(Z=1|2|3|4|5)
快速复用方式: 把SpatialCard.ets做成一个自定义组件,让不同应用通过参数传入:
zLevel: 1|2|3(决定阴影强度)content: () => void(卡片内部内容,可以是文字、图片或3D模型)onClick: () => void(点击事件)
各应用只需导入这个组件,传入不同的content即可,无需重复写shadow参数。
五步操作总览(无需理解,照着做)
| 步骤 | 操作 | 所需时间 |
|---|---|---|
| 1 | 确认环境(compileSdkVersion=26,hdc连接正常) | 5分钟 |
| 2 | 粘贴最小代码块,跑通一个Z轴卡片页面 | 10分钟 |
| 3 | 在卡片中嵌入GaussianModelView,显示3D模型 | 15分钟(需先有.gsplat文件) |
| 4 | 添加全屏3D查看器页面,支持跳转 | 20分钟 |
| 5 | 将通用组件抽离到/common-spatial,供其他应用复用 | 30分钟 |
抄作业清单
| 步骤 | 执行操作 | 预期输出/生效标志 |
|---|---|---|
| 1 | DevEco中确认 build.gradle 的 compileSdkVersion = 26 | 编译无版本报错 |
| 2 | 复制最小卡片代码至 Index.ets,启动模拟器运行 | 屏幕显示带阴影的三张卡片 + 底部悬浮按钮 |
| 3 | hdc push ./demo.gsplat /data/app/demo.gsplat | 终端输出 1 file pushed |
| 4 | 修改List item内容,嵌入GaussianModelView | 卡片内出现自动旋转的3D模型缩略图 |
| 5 | 新建 ModelViewer.ets,在卡片onClick中添加跳转 | 点击卡片跳转至全屏3D查看器,可手势旋转 |
| 6 | 将SpatialCard抽离为独立组件,参数传入zLevel和content | 其他页面3行代码即可复用空间化卡片 |
常见卡点
卡点1:编译报错 Cannot find module '@arkui.3D'
- 现象:红色波浪线在
import { GaussianModelView } from '@arkui.3D' - 修复:检查
oh-package.json5中是否包含"@arkui/3D": "^1.0.0",没有则手动添加后执行ohpm install - 验证:编译通过
卡点2:模拟器上 GaussianModelView 显示空白
- 原因:模拟器API 26镜像可能未完全包含3D渲染库
- 修复:确认模拟器版本为 HarmonyOS 7(API 26)镜像;如果仍不行,改用云手机或真机测试
- 验证:
hdc shell "ls -la /system/lib64/libark3d*"应有至少一个 .so 文件
卡点3:卡片点击无跳转
- 原因:未在
module.json5中注册 ModelViewer 页面 - 修复:在
module.json5的"pages"数组中添加"pages/ModelViewer" - 验证:
router.pushUrl()执行后页面切换成功
姐妹篇互指
这篇是“贴地版”——只管“怎么做”,不解释“为什么做”和“该不该做”。如果你需要判断“你的产品到底适不适合做空间化、从哪个页面切入ROI最高”,请阅读本篇的姐妹篇: 《空间计算的“认知门槛”:从2D铺大饼到3D叠千层的设计范式转型》 ,那是一套完整的战略决策框架。
文末声明
本文所有代码块与操作步骤,均基于HarmonyOS 7(API 26)、DevEco Studio 26.0.0.100验证。代码块可直接复制粘贴使用,但需根据实际工程路径调整.gsplat文件路径。模拟器环境下3D渲染可能存在性能差异,建议真机或云手机验证最终效果。不保证低版本API向下兼容。
作者
华夏之光永存
标签
#HarmonyOS #鸿蒙 #HarmonyOS7 #API26 #ArkUI #空间计算 #Z轴设计 #GaussianModelView #DevEcoStudio #初级工程师 #共创稿事节
本文对应征文活动「共创季·征文稿事节」第2期——探索HarmonyOS 7(API 26)的“空间 × AI 新视界”|方向一:空间化设计范式与转型探索(无真机可参与)
更多推荐


所有评论(0)