Hello World

运用窗口、体积和沉溺式空间向人们介绍地球。

概述

您能够运用 visionOS 场景类型和款式以有趣和引人入胜的方式共享信息。像体积和沉溺式空间这样的功能能够让您将交互式虚拟对象置于人们的环境中,或将人们置于虚拟环境中。

Hello World 运用程序运用这些工具来向人们介绍地球 – 我们所称之为家乡的星球。该运用程序展现了地球的歪斜如何产生时节,物体如何在绕地球运行时移动,以及地球在太空中的外观。

该运用程序运用 SwiftUI 来界说其界面,包括 2D 和 3D 元素。为了创立、自界说和办理 3D 模型和作用,它还依赖于 RealityKit 框架和 Reality Composer Pro。

创立运用程序的入口点

Hello World 在启动时构建了它要显现的场景 – 即呈现在 WorldApp 结构中的第一个场景 – 运用 WindowGroup:

WindowGroup("Hello World", id: "modules") {
    Modules()
        .environment(model)
}
.windowStyle(.plain)

与其他平台(例如 macOS 和 iOS)相似,visionOS 会将窗口组显现为一个熟悉的窗口外观。在 visionOS 中,人们能够调整窗口的巨细并将其移动到共享空间中。即便您的运用程序供给了复杂的 3D 体会,窗口也是运用程序的一个很好的起点,由于它能够让人们轻松进入体会。这也是供给指令或控件的好地方。

提示

这个特定的窗口组运用普通的窗口款式,以坚持对 visionOS 会自动增加的玻璃背景作用的操控。

运用导航仓库呈现不同的模块

在观看了一个简略的介绍性动画,显现出“Hello World”文本输入之后,界说了首要场景内容的 Modules 视图呈现了探索世界不同方面的选项。此视图包括了位于 NavigationStack 根部的目录:

NavigationStack(path: $model.navigationPath) {
    TableOfContents()
        .navigationDestination(for: Module.self) { module in
            ModuleDetail(module: module)
                .navigationTitle(module.eyebrow)
        }
}

在 visionOS 中,导航仓库的行为与其他平台相同。当它首次呈现时,仓库显现其根视图。当有人挑选嵌入的 NavigationLink 时,仓库会制作一个新视图并在工具栏中显现一个回来按钮。当有人点击回来按钮时,仓库会康复从前的视图。

visionOS示例代码:Hello World

屏幕截图显现了一个起浮在起居室中的 visionOS 窗口的左上角四分之一。在窗口的左上角呈现一个显现向左箭头的回来按钮。窗口的标题 A Day in the Life 呈现在按钮的右侧,并在笔直居中。窗口的首要部分显现了标题 Planet Earth,并显现了一些文本段落。

上述代码中 navigationDestination(for:destination:) 视图修饰符的尾部闭包在有人激活链接时显现一个视图,该链接根据来自相应链接的初始化器的模块输入:

NavigationLink(value: module) { /* The link's label. */ }

可能的模块值来自自界说的 Module 枚举:

enum Module: String, Identifiable, CaseIterable, Equatable {
    case globe, orbit, solar
    // ...
}

在新场景中显现一个交互式地球

地球模块以一些关于地球的事真实主窗口中开启,周围是一个支撑内容的装饰性平面图画。为了帮助人们更好地了解,该模块还包括一个名为 View Globe 的按钮,点击该按钮能够在一个新窗口中翻开一个交互式 3D 地球。

visionOS示例代码:Hello World

起浮在起居室中的 visionOS 窗口的截图。窗口的左上角呈现一个左指向的 Chevron 形状的回来按钮。窗口的标题 A Day in the Life 呈现在按钮的右侧,并在笔直居中。窗口的主体部分显现了标题 Planet Earth,以及几段关于地球的文本。

为了能够翻开多种场景类型,Hello World 在其信息属性列表文件中包括了 UIApplicationSceneManifest 键。这个键的值是一个字典,其间包括了一个带有值为 true 的 UIApplicationSupportsMultipleScenes 键:

<key>UIApplicationSceneManifest</key>
<dict> 
    <key>UIApplicationSupportsMultipleScenes</key> 
    <true/> 
    <key>UISceneConfigurations</key> 
    <dict/> 
</dict>

为地球声明一个体积窗口

在设置了密钥之后,运用程序在其 App 声明中运用了第二个 WindowGroup。这个新的窗口组运用 Globe 视图作为其内容:

WindowGroup(id: Module.globe.name) {
    Globe() .environment(model) 
}
.windowStyle(.volumetric) 
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)

这个窗口组创立了一个具有任意深度的窗口,十分合适在行为相似于通明盒子的有界区域中显现交互式的 3D 模型,由于 Hello World 运用了 volumetric window style 场景修饰符。人们能够像操作其他窗口相同在 Shared Space 中移动这个盒子,而内容会坚持固定。defaultSize(width:height:depth:in:) 修饰符在米单位下指定了窗口的巨细,包括深度维度。

Globe 视图包括 3D 内容,但仍然只是一个 SwiftUI 视图。它包括两个元素在 ZStack 中:一个子视图制作地球的模型,另一个供给了一个操控面板,人们能够用来装备模型的外观。

翻开和封闭地球仪窗口

地球模块呈现一个 View Globe 按钮,人们能够点击它来显现体积窗口或封闭窗口,这取决于当时的状况。Hello World 经过创立一个带有按钮款式的 Toggle,并将其嵌套在一个自界说的可重用 WindowToggle 视图中来完成这种行为。

visionOS示例代码:Hello World

一个在起居室中起浮的 visionOS 窗口的左下角截图,呈现在太空中的地球仪的右边,被左边的光照亮。窗口包括几段文字和一个高亮显现的 View Globe 按钮。一个操控面板下面起浮着四个圆形按钮。操控面板中的第一个按钮包括太阳图标而且是高亮的。其他按钮,没有一个是高亮的,别离包括了一个大头针和椭圆、圆形箭头以及云和太阳的图标。

private struct WindowToggle: View {
    var title: String 
    var id: String 
    @Binding var isShowing: Bool 
    @Environment(\.openWindow) private var openWindow 
    @Environment(\.dismissWindow) private var dismissWindow 
    var body: some View { 
        Toggle(title, isOn: $isShowing) 
            .onChange(of: isShowing) { wasShowing, isShowing in 
                if isShowing { 
                    openWindow(id: id) 
                } else { 
                    dismissWindow(id: id) 
                } 
        } 
        .toggleStyle(.button) 
    } 
}

当有人点击开关时,isShowing 状况会发生改变,onChange(of:initial:_:) 修饰符会调用 openWindow 或 dismissWindow 动作来翻开或封闭窗口。视图从环境中获取这些动作,并运用与窗口标识符匹配的标识符。

展现绕地球运行的物体

在 visionOS 中,你能够像在其他平台中相同运用窗口。可是,在 visionOS 中,窗口供给了少量的深度,你能够用来创立 3D 作用,例如呈现在其他元素前面的元素。Hello World 利用这种深度来在 2D 内容中呈现小型模型。

运用程序的第二个模块,Objects in Orbit,供给关于绕地球运行的物体(如月球和人造卫星)的信息。为了让人们了解这些物体的外观,该模块直接在窗口中显现这些物体的 3D 模型。

visionOS示例代码:Hello World

一个以角度检查的 visionOS 窗口的右侧截图。在窗口的左侧,有一个标题和几段文字部分可见,但在图画中大部分被裁剪掉了。窗口的右侧包括一个分段控件和一个 3D 模型。控件上有“Satellite”、“Moon”和“Telescope”的文本,其间第一个被选中。3D 模型带有太阳能电池板和卫星天线,位于窗口外表的前方。

Hello World 运用一个自界说的 ItemView 结构从资源包中加载这些模型,该视图包括一个 Model3D 结构。该视图会对模型进行缩放和定位,以适应可用空间,并运用可选的方向调整:

private struct ItemView: View {
    var item: Item 
    var orientation: SIMD3<Double> = .zero var body: 
    some View { 
        Model3D(named: item.name, bundle: worldAssetsBundle) { model in 
            model.resizable() 
                .scaledToFit() 
                .rotation3DEffect( 
                    Rotation3D( 
                        eulerAngles: .init(angles: orientation, order: .xyz) 
                    ) 
                 ) 
                 .frame(depth: modelDepth) .offset(z: -modelDepth / 2) 
         } placeholder: { 
             ProgressView() 
                 .offset(z: -modelDepth * 0.75) 
         } 
    } 
}

运用程序会为每个模型运用一次此 ItemView,将每个模型放在一个覆盖层中,该覆盖层仅在根据当时挑选时可见。例如,以下覆盖层在 x 轴和 z 轴上稍微歪斜的情况下显现卫星模型:

.overlay {
    ItemView(item: .satellite, orientation: [0.15, 0, 0.15]) 
        .opacity(selection == .satellite ? 1 : 0)
}

包括这些模型的 VStack 还包括一个 Picker,人们能够运用它来挑选要检查的模型:

Picker("Satellite", selection: $selection) {
    ForEach(Item.allCases) { item in 
        Text(item.name)
    } 
} .pickerStyle(.segmented)
在向 2D 窗口增加 3D 作用时,请记住以下几点指导:
  • 不要过度运用。这些类型的作用增加了趣味性,但可能会在人们从不同方向检查窗口时无意中遮挡重要的控件或信息。

  • 保证元素不超越可用的深度。过度的深度会导致元素被剪切。考虑在初始放置后可能发生的任何方位或方向改变。

  • 防止模型与背景玻璃相交。同样,在初始放置后考虑潜在的移动。

在沉溺式空间中展现地球与其卫星的联系

人们能够经过运用程序的轨道模块来可视化卫星绕地球运动,该模块将地球、月球和通信卫星一同显现为一个单一的体系。人们能够将这个体系移动到环境中的任何方位,或者运用规范手势调整其巨细。他们还能够在体系周围移动自己,以取得不同的视角。

一个在起居室中起浮的 visionOS 窗口的左下角截图,呈现在太空中的地球-月球体系的右边,被右边的光照亮。窗口包括几段文字和一个高亮显现的 View Orbits 按钮。一个细长的轨道环绕着地球,从底部开端,然后在地球的上方构成一个圆圈。

注:

要了解在 visionOS 中设计手势,请阅览人机界面指南中的手势部分。

为了创立这个可视化作用,运用程序在一个混合沉溺式款式的 ImmersiveSpace 场景中显现 Orbit 视图,其间包括一个用于建模整个体系的单一 RealityView:

ImmersiveSpace(id: Module.orbit.name) {
    Orbit() .environment(model) 
} 
.immersionStyle(selection: $orbitImmersionStyle, in: .mixed)

与 visionOS 运用程序中的任何非必须场景相同,此场景依赖于在信息属性列表文件中拥有 UIApplicationSupportsMultipleScenes 键。该运用程序还运用了相似于用于窗口的通用切换视图来翻开和封闭空间:

private struct SpaceToggle: View {
    var title: String 
    var id: String 
    @Binding var isShowing: Bool
    @Environment(\.openImmersiveSpace) private var openImmersiveSpace 
    @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace 
    var body: some View { 
        Toggle(title, isOn: $isShowing) 
            .onChange(of: isShowing) { wasShowing, isShowing in 
                Task { 
                    if isShowing { await openImmersiveSpace(id: id) 
                } else { 
                    await dismissImmersiveSpace() 
                } 
            } 
        } 
        .toggleStyle(.button) 
    } 
}

与在“翻开和封闭地球窗口”部分中呈现的窗口等效切换比较,有一些关键的区别:

  • SpaceToggle 运用了环境中的 openImmersiveSpace 和 dismissImmersiveSpace,而不是窗口的等效项。

  • 在这种情况下,dismiss 操作不需要标识符,由于人们一次只能翻开一个空间,即便跨运用程序也是如此。

  • 空间的翻开和封闭操作是异步的,因此它们呈现在一个 Task 内。

从空间中以全沉溺的方式检查太阳系

运用程序的最后一个模块让人们感触地球在太阳系中的方位。与其他模块相同,这个模块包括信息和装饰性图画,以及一个按钮,导向另一个可视化作用,让人们能够从太空中体会地球。

当用户点击按钮时,运用程序会接管整个显现屏,并在所有方向上显现星星,您能够在右侧的视频中看到。地球直接在前方,月球在右侧,太阳在左侧。主窗口还显现了一个小型操控面板,人们能够用它来退出彻底沉溺式体会。

visionOS示例代码:Hello World

截图显现了地球的一小部分位于星空之中,右侧可见一个窗口。云朵呈现在被照亮的部分,而地面的光线则在漆黑的部分可见。窗口的标题为“太阳系”,标题两侧别离有向左和向右的箭头,别离表明撤退和行进。撤退按钮被调暗。标题下方有一句话,标题下方还有一个标题为“退出太阳系”的按钮。

提示

人们能够经过按下设备的 Digital Crown 来退出全沉溺模式,但通常情况下,您会为您的运用程序供给内置的机制来坚持对体会的操控。

该运用程序在此模块中还运用了另一个沉溺式空间场景,但此场景运用了封闭透视视频的全沉溺风格:

ImmersiveSpace(id: Module.solar.name) {
    SolarSystem() .environment(model)
} 
.immersionStyle(selection: $solarImmersionStyle, in: .full)

这个场景依赖于其他非必须场景所运用的相同的 UIApplicationSupportsMultipleScenes 键,而且经过前面描绘的自界说 SpaceToggle 激活,但在这种情况下运用了 Module.solar.id 场景标识符。

为了在太阳系控件中重用主窗口,Hello World 将导航栈和控件都放置在一个 ZStack 中,然后设置每个控件的不通明度,以保证每次只显现一个:

ZStack {
    SolarSystemControls() 
        .opacity(model.isShowingSolar ? 1 : 0) 
    NavigationStack(path: $model.navigationPath) { 
        // ... 
    } 
    .opacity(model.isShowingSolar ? 0 : 1) 
} .animation(.default, value: model.isShowingSolar)