Go beyond the window with SwiftUI
Swift & UI 进阶 20m

用 SwiftUI 超越窗口

Go beyond the window with SwiftUI

2023年6月5日

在 Apple 官方观看视频

一句话判断

三行代码就能把你的 SwiftUI 视图变成一个沉浸式空间体验——ImmersiveSpace 就是这么简单。

这场 Session 讲了什么

SwiftUI 在空间计算平台上引入了 ImmersiveSpace(沉浸空间)场景类型。与 WindowGroup 和 Volume 并列,ImmersiveSpace 让你的内容可以不受窗口边界限制,充满整个空间。

当你的 app 打开一个 ImmersiveSpace 时,app 进入 Full Space 模式——其他所有 app 消失,为你的内容让路。关闭空间后,其他 app 重新出现。app 同时只能打开一个空间。

SwiftUI 提供了 openImmersiveSpacedismissImmersiveSpace 环境 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 上放置内容
WWDC 2023