[VisionOS] 拆分HelloWorld的功能点 - 沉浸式与窗口之间的切换

背景

在体验HelloWorld时,很好奇每个功能是怎么实现的,但是这个demo复用了很多功能、数据模型,刚开始理解起来就比较困难。所以我就先从功能点来看,将复用的功能、数据模型都剔除掉,保证单一功能能解藕单独运行。

环境

Xcode:15.1 beta

VisionOS:1.0

梳理功能

graph LR; 功能点-->A(设置光照); style A fill:#bbf,color:#fff click A "https://juejin.cn/post/7298690615046651943" 功能点-->B(手势转动地球) style B fill:#bbf,color:#fff click B "https://juejin.cn/post/7298765809290706983" 功能点-->C(地球自转) style C fill:#bbf,color:#fff click C "https://juejin.cn/post/7298775642261569575" 功能点-->D(地球跟随鼠标拖动) style D fill:#bbf,color:#fff click D "https://juejin.cn/post/7299037876637351975" 功能点-->E(卫星围绕地球转动) style E fill:#bbf,color:#fff click E "https://juejin.cn/post/7300431522255241250" 功能点-->G(沉浸式与窗口之间的切换) style G fill:#bbf,color:#fff click G "https://juejin.cn/spost/7300816733525901352"

沉浸式与窗口之间的切换

1. 打开沉浸式空间

swift 复制代码
import SwiftUI

@main
struct MyWorldApp: App {
    @State private var solarImmersionStyle: ImmersionStyle = .full

    @State private var model = ViewModel()

    var body: some Scene {
        // 1.不带边框的window
        WindowGroup{
            SolarDisplayView()
                .environment(model)
        }
        .windowStyle(.plain)
        
        // 2.沉浸式空间
        ImmersiveSpace(id: Module.solar.name) {
            SolarView()
                .environment(model)
        }
        .immersionStyle(selection: $solarImmersionStyle, in: .full)
    }
    
    // 3. 注册的Component、System
    init() {
        RotationComponent.registerComponent()
        RotationSystem.registerSystem()
        TraceComponent.registerComponent()
        TraceSystem.registerSystem()
    }
}

1.1 定义沉浸式空间

在打开沉浸式空间之前,我们需要定义一个沉浸式空间,在App里面作为Scene返回。

Swift 复制代码
ImmersiveSpace(id: Module.solar.name) {
    SolarView()
        .environment(model)
}

1.2 打开/关闭空间

swift 复制代码
// 打开
@Environment(\.openImmersiveSpace) private var openImmersiveSpace
Task {
    await openImmersiveSpace(id: Module.solar.name)
}
swift 复制代码
// 关闭
@Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
Task {
    await dismissImmersiveSpace()
}

注意: 我们在打开空间openImmersiveSpace后,之前的window并不会消失,还会一直保留。也就是说,即使你进入了沉浸式空间后,之前的window也会进入沉浸式空间,同一时间会存在一个window、一个space。

为了更多集中在Space上面,我们常常会对之前的window做一些隐藏、关闭等操作。

2.隐藏window

这里的隐藏,就是改变原有Window的透明度,把无关的信息隐藏掉,看起来window就"消失"了,其实它并没有关闭。

swift 复制代码
WindowGroup{
    SolarDisplayView()
        .environment(model)
}
.windowStyle(.plain)

在隐藏之前,一定要设置.windowStyle(.plain),不然会一直显示毛玻璃窗口。

swift 复制代码
import SwiftUI

// 进入沉浸式空间的入口
struct SolarDisplayView: View {
    @Environment(ViewModel.self) private var model
    
    var body: some View {
        ZStack {
            // 退出沉浸式空间的开关
            SolarSystemToggle()
                .opacity(model.isShowingSolar ? 1 : 0)
            VStack{
                Text("进入沉浸式空间")
                    .font(.system(size: 50, weight: .bold))
                    .padding(.bottom, 15)
                // 进入沉浸式空间的开关
                SolarSystemToggle()
            }
            .opacity(model.isShowingSolar ? 0 : 1)
        }
    }
}

#Preview {
    SolarDisplayView()
        .environment(ViewModel())
}

这里逻辑很简单,就是进入沉浸式空间前,显示进入开关。

进入沉浸式空间后,显示退出开关,其实是同一个window。

这里会有几个疑问:

1. 为什么不直接关闭Window
swift 复制代码
@Environment(\.dismissWindow) private var dismissWindow
Task {
    await dismissWindow()
}

我们确实可以先关闭window,然后再打开window,但实际使用过程中会出现闪烁的情况,所以才使用隐藏、显示。

2. 退出开关还可以怎么做?

可以直接放在Space空间,但是需要自己调整位置

可以用RealityView.attachment,也需要调整位置

3. 为什么Space、window可以同时存在

我最开始会有这个疑问,为什么能同时存在,做成导航栈一样岂不是更好,一个打开,另一个关闭。直到我看到Destination Video,我才知道它们一起存在的意义。里面展示一个视频播放的demo,最开始是一个视频列表窗口,有导航栈点击进入详情。详情展示了播放窗口,又展示了一个全景的沉浸式空间。在接触这个demo之前,我一直以为播放器也在沉浸式空间里面,但是始终没有达到想要的效果,最终才发现window、space同时存在才能实现。

3.代码

入口是SolarDisplayViewMyWorldApp启动入口也是它,直接Run就可以。

相关推荐
HarderCoder6 个月前
Apple Vision Pro 学习资料
visionos
苹果API搬运工6 个月前
试玩 RealityComposerPro 中的 Shader Graph:用圆环制作一个 Meta Logo
visionos·增强现实
苹果API搬运工6 个月前
我开源了个手势匹配框架,让你在模拟器调试 visionOS 手部追踪功能!
visionos·增强现实
苹果API搬运工6 个月前
只需三板斧!带你入门 visionOS 空间计算的数学与几何基础
visionos·增强现实
-九月新辰-6 个月前
Unity VisionOS开发流程
unity·游戏引擎·visionos
XR基地7 个月前
XR 世界导览021 | AVP App Store上线网页版、如何在AVP上快速匹配手势、AVP开发岗位
visionos
XR基地7 个月前
XR 世界导览#020-visionOS 1.1/Xcode 17.3/PICO 5.9.0 更新了!
unity3d·visionos
xChester7 个月前
visionOS 应用图标设计
前端·ios·visionos
XR基地7 个月前
XR 世界导览#019-Let's visionOS 大会/在 AVP 上玩手机或查看Spline的3D模型/用代码写ShaderGraph
unity3d·visionos
xChester7 个月前
VisionPro开发 - 轻松实现天空盒并添加光照
前端·ios·visionos