布景

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

环境

Xcode:15.1 beta

VisionOS:1.0

梳理功用

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

沉溺式与窗口之间的切换

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

1. 翻开沉溺式空间

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回来。

ImmersiveSpace(id: Module.solar.name) {
    SolarView()
        .environment(model)
}

1.2 翻开/封闭空间

// 翻开
@Environment(.openImmersiveSpace) private var openImmersiveSpace
Task {
    await openImmersiveSpace(id: Module.solar.name)
}
// 封闭
@Environment(.dismissImmersiveSpace) private var dismissImmersiveSpace
Task {
    await dismissImmersiveSpace()
}

留意: 咱们在翻开空间openImmersiveSpace后,之前的window并不会消失,还会一向保存。也便是说,即便你进入了沉溺式空间后,之前的window也会进入沉溺式空间,同一时间会存在一个window、一个space。

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

2.躲藏window

这儿的躲藏,便是改动原有Window的透明度,把无关的信息躲藏掉,看起来window就“消失”了,其实它并没有封闭。

WindowGroup{
    SolarDisplayView()
        .environment(model)
}
.windowStyle(.plain)

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

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
@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就能够。