用 SwiftUI 超越窗口
Go beyond the window with SwiftUI
2023年6月5日
一句话判断
三行代码就能把你的 SwiftUI 视图变成一个沉浸式空间体验——ImmersiveSpace 就是这么简单。
这场 Session 讲了什么
SwiftUI 在空间计算平台上引入了 ImmersiveSpace(沉浸空间)场景类型。与 WindowGroup 和 Volume 并列,ImmersiveSpace 让你的内容可以不受窗口边界限制,充满整个空间。
当你的 app 打开一个 ImmersiveSpace 时,app 进入 Full Space 模式——其他所有 app 消失,为你的内容让路。关闭空间后,其他 app 重新出现。app 同时只能打开一个空间。
SwiftUI 提供了 openImmersiveSpace 和 dismissImmersiveSpace 环境 action 来控制空间的打开和关闭。ImmersiveSpace 与 RealityView 深度集成——RealityView 支持异步加载资源、在 ARKit anchor 上放置元素,以及访问手部和头部姿态数据。
坐标系方面有一个需要注意的差异。SwiftUI 布局系统中 y 轴向下、z 轴朝向你。而 RealityKit 中 y 轴向上。在 RealityView 中定位实体时使用 RealityKit 的坐标约定。
值得深挖的点
空间的原点位于用户脚下附近。这意味着你不能简单地把内容放在默认位置——需要主动定位到合适的空间位置。RealityView 的异步资源加载功能非常适合在空间中展示复杂的 3D 内容。
ImmersiveSpace 有两种样式:Mixed(混合)和 Full(完全)。Mixed 模式下用户仍然可以看到周围环境,适合增强现实体验。Full 模式完全覆盖用户视野,适合全沉浸式体验(如游戏)。
代码片段
// 定义沉浸空间
@main
struct WorldApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "solar") {
SolarSystemView()
}
}
}
// 打开和关闭沉浸空间
struct ContentView: View {
@Environment(\.openImmersiveSpace) var openSpace
@Environment(\.dismissImmersiveSpace) var closeSpace
var body: some View {
Button("探索太阳系") {
Task {
await openSpace(id: "solar")
}
}
}
}
// 配合 RealityView 使用
ImmersiveSpace {
RealityView { content in
let starfield = try await Entity(named: "Starfield")
content.add(starfield)
}
}
.immersiveSpaceStyle(.mixed) // 或 .full
最佳实践
- 使用 identifier 管理多个 ImmersiveSpace 定义
- 配合 RealityView 实现丰富的 3D 内容展示
- 注意坐标系差异——RealityView 中使用 RealityKit 坐标
- 根据体验类型选择 Mixed 或 Full 样式
- 关闭空间后其他 app 自动恢复
还有什么值得关注
- 参考 “Build spatial experiences with RealityKit” 了解 RealityView 详情
- 空间中可以访问手部和头部姿态数据
- 系统自动处理空间的进入和退出动画
- RealityView 支持在 ARKit anchor 上放置内容