View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

返回 WWDC25

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 借助 SwiftUI 在 visionOS 中设置场景

    探索精彩的全新 API,为你的 visionOS App 打造更出色的窗口、空间容器和沉浸式空间。微调场景在重新启动或固定位置时的行为。通过裁剪边缘和对齐,根据周边环境来调整空间容器。将流媒体格式的沉浸式内容从 Mac 传输到 Apple Vision Pro。借助空间容器和沉浸式空间,让基于 UIKit 的现有 App 更上一层楼。

    章节

    • 0:00 - 简介
    • 2:11 - 启动或固定位置
    • 8:15 - 视体增强功能
    • 15:58 - 沉浸式空间
    • 22:16 - Scene Bridging
    • 24:01 - 后续步骤

    资源

    • Adopting best practices for persistent UI
    • Canyon Crosser: Building a volumetric hike-planning app
    • Petite Asteroids: Building a volumetric visionOS game
    • Tracking accessories in volumetric windows
      • 高清视频
      • 标清视频

    相关视频

    WWDC25

    • 小组件的新功能
    • 搭配使用更出色:SwiftUI 和 RealityKit
    • 用于打造沉浸式 App 的 Metal 渲染的新功能
  • 搜索此视频…

    大家好 我叫 Miguel 是 SwiftUI 团队的工程师 在这个视频中 我们将介绍 visionOS 26 为场景带来的一些强大新功能 也许你还能学到如何打造 属于自己的场景

    visionOS 支持三种场景类型: 窗口、空间容器和沉浸式空间 App 可以灵活组合这些场景 创造出独特而精彩的体验

    今天我们将探索适用于这三种场景 的新 API 还有一些更侧重于空间容器和 沉浸式空间 我的朋友 Maks、Amanda 和 Trevor 正在对 BOTanist 进行一些 令人兴奋的改进 这款游戏是关于如何帮助一位机器人 在空中花园中培育美丽植物

    至于我 我一直在开发一款 App 通过构建场景与装饰 帮助这些机器人朋友将莎士比亚 笔下的人物栩栩如生地展现出来 并投身到表演的世界中

    打开我的 App 会看到一个舞台选择画面 我们来创建一个新舞台吧

    现在 我可以在舞台上 四处移动 BOTanist 来布置场景

    通过这个功能 我就能让机器人朋友 上演我最爱的剧目 比如《罗波与茱丽叶》

    接下来我们就来看一看 visionOS 26 的全新场景 API 如何进一步提升我的 App

    首先 我们来看看 visionOS 26 中 新增的生命周期 API 它们可以帮助在窗口启动和锁定到 房间时定义行为逻辑

    接着 我会介绍根据用户周围环境 自适应的空间容器增强功能

    然后 我会添加一个 RemoteImmersiveSpace 以从 macOS App 中预览我在 Apple Vision Pro 上构建的场景

    最后 对于现有的 UIKit App 我们会使用全新的场景桥接 API 添加这些强大的空间容器与 沉浸式体验

    我们先从窗口的启动与锁定讲起

    visionOS 26 引入了一些来自 macOS 的生命周期 API 这些 API 非常实用 我们会介绍用于管理场景恢复、 App 启动 以及创建唯一窗口的 API

    在 visionOS 26 中 用户现在可以将窗口、空间容器 甚至全新的小组件锁定到 周围物理环境中的 特定房间 从而持久保留这些元素

    这有助于让虚拟内容在 它们所在的空间中更有“存在感” 这些被锁定的窗口会绑定到使用 它们的房间

    当用户稍后再次进入这个房间 窗口会自动恢复显示

    结合锁定功能的场景恢复体验 非常出色 我可以保留所有窗口 并在需要时回到原来的状态

    通常 用户会希望能锁定所有窗口 并由系统自动恢复 因此 大多数场景应当默认 启用恢复 系统会自动为你处理

    不过 有些窗口并不适合 以这种方式持久存在

    像欢迎界面、依赖上下文的 UI (例如与某个 App 状态绑定的 工具窗口) 或是已完成的一次性操作 (如登录提示) 等瞬态元素都可以考虑停用场景恢复

    我在 App 中加入了沉浸式模式 让用户能充分体验 我们最爱的机器人 这时工具栏会变成一个独立的 工具窗口 悬浮在面前 方便在沉浸状态下操作舞台

    需要注意的是 沉浸式空间 不会被恢复

    也就是说 当再次进入这个房间时 沉浸式空间不会恢复

    但如果之前在空间中锁定了 工具窗口 它可能会单独出现 而没有任何可供修改的内容

    为避免出现这种意外的状态 我可以为 WindowGroup 添加 .restorationBehavior(.disabled) 修饰符 明确表示这个工具窗口不参与恢复 也不会被锁定

    这样 当用户稍后再次进入这个 房间时 这个多余的窗口就不会出现了

    启动 App 时 系统会显示 第一个窗口 作为全新会话的起点

    在 UIKit 中 你可以通过新的 destructionConditions API 并设置 .systemDisconnection 属性来停用 UI 场景的恢复 如需了解更多信息 请查看相关文档

    有些情况下 动态决定启动时显示 哪个场景会 对 App 很有帮助

    例如 我希望在 App 首次启动时 先展示一个 向用户问好的欢迎窗口 然后再进入舞台选择界面

    为了根据 App 状态来自定启动时 显示的窗口 我可以使用 defaultLaunchBehavior 修饰符

    在这里 我将欢迎窗口设置为 优先显示:当检测到是第一次 启动 App 时 将它标记为 presented

    在这个窗口出现后 我可以关闭 这个值 因为我不需要再显示这个窗口了

    请注意 所选启动窗口的角色必须 与 Info.plist 中 Application Scene Manifest 的 Preferred Default Scene Session Role 属性匹配

    这意味着 如果我将默认的 场景会话角色设置为 Window 系统在启动 App 时只会考虑普通 窗口场景

    在这种情况下 空间容器即使设定了 用于获得优先考虑的 defaultLaunchBehavior 也仍然会被忽略 所以请确保你希望展示的场景 与场景会话角色相匹配

    对于 defaultLaunchBehavior 修饰符 还有一个非常 实用的小技巧

    之前我提到过 我不希望在返回 房间时 让工具面板自动恢复 以及如何使用 restorationBehavior 来解决这个问题 现在我遇到一个类似的问题

    如果我通过按下数码旋钮 退出沉浸式空间 并关闭工具窗口

    当再次启动 App 时 这个窗口仍然会回来

    导致出现与自动恢复类似的 异常状态

    我真正想要的是:从舞台创建 窗口开始 让 App 从一个安全状态启动

    为此 我可以为工具窗口添加 defaultLaunchBehavior(.suppressed) 修饰符 告知系统在从主屏幕视图 启动 App 时 不要恢复这个窗口

    通常情况下 对于次级场景 建议使用 .suppressed defaultLaunchBehavior 以避免用户陷入 意料之外的界面状态

    在 UIKit 中 你可以通过为 UIScene 的 destructionConditions 添加 userInitiatedDismissal 选项 实现相同的行为

    visionOS 26 还增加了 对创建唯一窗口的支持

    这类窗口不能被复制 同一时间只能存在唯一的实例

    就像在 Mac 上一样 你需要使用 Window API 而不是 WindowGroup 来声明它们

    你可以使用它们来避免重复创建 关键界面 例如游戏窗口或视频通话界面

    也可以用它们来实现只需要单一 实例的辅助功能

    比如欢迎窗口就不需要多个实例 所以我将它改为一个唯一窗口

    而主舞台空间容器仍然保留为 WindowGroup 这样我就可以同时创建多个舞台

    非常棒 现在我的 App 生命周期管理 比以往任何时候都要好 我们自定了在锁定与 App 启动时 应显示哪些窗口 并在合适的场景下 保持窗口的唯一性

    visionOS 26 中还引入了大量 空间容器的增强功能 能让你的空间容器更加立体出色

    接下来我会介绍新的表面吸附特性 展示类型的改进 以及 Clipping Margins API

    我们这就开始吧

    在 visionOS 26 中 用户现在可以 将窗口和空间容器 吸附在物理环境中 只需轻轻将窗口移近某个表面 即可完成吸附 对于可恢复的窗口 这也意味着这个 窗口将“锁定” 从而实现持久存在

    窗口的背面可以吸附在垂直表面上 例如墙壁 空间容器的底部可以吸附在 水平表面上 比如地板或桌面

    而 visionOS 26 新引入的小组件 则可以吸附到任意类型的表面

    要进一步了解如何将小组件添加到 你的 visionOS App 欢迎观看讲座“小组件的新功能”

    对于窗口和空间容器 现在你甚至可以获取 吸附事件的相关信息

    比如在我的 App 中 我可以将 空间容器吸附到桌面上 并使它水平锚定

    这只是开始 我还希望让舞台在空间中显得 更“真实” 我希望当空间容器吸附到桌面时 机器人能直接站在桌面上

    通过全新的 SurfaceSnappingInfo API 我们可以获取吸附状态的相关信息

    这个 API 提供了一个简单的 isSnapped 属性 用来判断窗口大致的吸附状态

    对于更复杂的使用场景 还可以获取 ARKit 提供的 贴附表面的分类信息 注意 这类详细信息需要用户授权 我来演示如何启用

    要启用详细的吸附表面信息 首先需要 将 Application Wants Detailed Surface Info 设为 YES 还需要添加 Privacy World-Sensing Usage-Description 并写上你希望在请求权限时 展示的说明

    这两个键值可以在 App 的 Info.plist 中设置

    完成设置后 我们就可以进入代码了

    在这里 我从环境中获取 surfaceSnappingInfo

    并在 onChange 中检查当前场景 是否已吸附 并检查我是否有权限访问吸附 表面的分类信息

    检查 authorizationStatus 会在需要时 自动请求用户授权

    现在 当吸附到桌面时 我希望隐藏舞台下方的底座 我用一个状态变量来控制这一行为

    这样一来 我就可以将空间容器 吸附到桌子上 并让机器人 在我自己的环境中尽情表演了 太棒了!

    此外 我还实现了这样的功能: 当我绕着桌子走动时 会隐藏那些挡住我视线的墙面 这样我就始终能看到空间容器内部

    这部分是通过使用 onVolumeViewpointChange 修饰符 对场景视角的变化做出反应而实现的

    要想了解更多信息 欢迎观看 WWDC24 的讲座 “深入探究空间容器和沉浸式空间” 看看 Owen 是如何将它添加到 BOTanist 里的

    我还希望用户可以在舞台周围 自由放置新的道具 可以在容器空间的工具栏中加入一个 弹出窗口 里面可选择要添加的道具

    太棒了!我终于可以重现《Tragedy of King Gear》的精彩场景了

    之前 展示类型仅在 Windows 中受支持

    从 visionOS 2.4 开始 新增了对嵌套展示类型的支持 例如从工作表中展示弹出窗口 或从装饰元素中展示上下文菜单

    现在 随着 visionOS 26 的推出 展示类型获得了一套全新的数据来源 你可以从空间容器内部、 空间容器的装饰元素、 RealityView 的附件 甚至直接在 RealityKit 中通过 PresentationComponent 来展示内容

    如果你想进一步了解如何结合 RealityKit 使用附件和 PresentationComponent 创建 展示类型 欢迎观看讲座“搭配使用更出色: SwiftUI 和 RealityKit”

    这不仅适用于部分类型 而是支持所有展示类型 包括菜单、工具提示、 弹出窗口、工作表、提示框 和确认对话框

    欢迎查阅相关文档 了解如何使用 SwiftUI 来创建这些展示类型

    所有展示类型都有特殊的 视觉处理方式 即使被 3D 内容遮挡时也能保持可见

    默认情况下 它们会与遮挡内容 巧妙融合

    不过 你也可以自定为 穿透遮挡层或完全被遮挡

    可使用 subtle、prominent 或 none 三种选项来调整效果

    这些选项可以通过 presentationBreakthroughEffect 修饰符应用到展示类型上

    对于除展示类型之外的其他元素 则可使用 breakthroughEffect 修饰符实现同样效果

    有了展示类型元素 现在我可以 在任何位置添加自定 UI 了 我们再来加点东西

    我添加了另一个弹出菜单 用于更换舞台布景 这样 我们的机器人朋友就能 从老旧剧场转场到热带海岛 正好适合上演《The Tempest》!

    这个布景已经很有看头 但我想再添点精彩效果 加个瀑布怎么样? 再加些雷声隆隆的云团

    不过 我希望这些元素不会挤占 舞台中央的主要表演区域 这时就可以用上全新的裁剪边距功能

    在空间容器中 可以使用新的 preferredWindowClippingMargins API 来渲染场景边界之外的内容

    这部分内容不可交互 因此应仅用于视觉效果展示

    需要注意的是 系统可能不会 授予所请求的边界 因此 可以通过 windowClippingMargins 环境变量 读取实际授予的边距

    我们来看看具体的代码

    我可以用 preferredWindowClippingMargins API 指定想要的裁剪边距 这里我希望设置底部的裁剪边距

    我要确保将以米为单位的 maxWaterfallHeight 转换为点数 方法是乘以从 PhysicalMetric 获取的 pointsPerMeter 系数

    接着 我使用 windowClippingMargins 环境变量 读取系统授予的边距

    这样 我就可以缩放瀑布的尺寸 以便在边距范围内渲染

    我取边距值与瀑布高度中的较小值 确保无论系统授予多少边距 都能完整渲染瀑布模型

    完成了! 看起来好多了 云层营造出暴风雨的氛围 瀑布在底板下方渲染 不会抬高内容 舞台焦点依然集中在海岛和 机器人身上

    希望 BOTanist 已加满机油

    就这样 我们的最新剧场演出 比以往都更真实 借助吸附功能和裁剪边距 内容可以自然适应物理空间 而借助展示类型功能 我们可以构建强大的界面 打造理想的舞台场景

    接下来 我来看看还能如何提升 App 的沉浸式体验

    沉浸式空间可让你的空间体验 环绕在四周 visionOS 26 引入了一些 很棒的新方式 让你能在沉浸式环境中成就更多精彩

    我将会介绍以下内容:世界重新定位 事件、沉浸样式的新功能、 macOS 上的远程沉浸式空间支持 以及升级为基于 Compositor 的 沉浸式空间 以使用 Metal 进行渲染 用户在空间中移动时可以长按 数码旋钮 将 App 的体验重新定位到他们周围

    如果你的 App 使用了 ARKit 数据 这可能会使 你之前保存的位置失效

    你可以通过新的 onWorldRecenter 视图修饰符 监听世界重新定位事件 以便及时响应

    这对于在新的坐标系下重新计算 并保存位置非常有用

    visionOS 26 还为沉浸式 空间的多种沉浸样式 引入了新的自定选项

    渐进式沉浸样式 是一种很好的方式 可以在保持用户 与现实世界连接的同时 部分展示沉浸式空间

    沉浸式内容会呈现在一个可调整大小 的传送门中 用户可通过旋转 数码旋钮来调整它的尺寸

    沉浸范围可在渐进式沉浸样式中 进行自定

    在 visionOS 26 中 你还可以自定 传送门的宽高比 你可以使用现有的横向宽高比 或全新的纵向宽高比

    对于垂直方向的体验 例如 将 iPhone 游戏带到 Apple Vision Pro 上 或者包含 大量运动内容的体验 建议使用纵向宽高比 因为在周围保持稳定的环境 有助于提升用户的舒适感

    你可以像设置沉浸范围一样 通过为 progressive 样式提供 一个参数来指定这一宽高比

    除了 progressive 样式 mixed 沉浸样式也新增了自定选项 可用于自定沉浸式空间

    当沉浸样式设为 mixed 时 沉浸式空间的内容会与用户周围的 环境融合

    这是我在 App 中默认使用的样式

    在 visionOS 26 中 沉浸式内容 还能与系统环境融合 也就是说 我可以在月球上 观看我的机器人上演的最新剧目

    要实现这一点 可以使用 immersiveEnvironmentBehavior 场景修饰符 并设置为 coexist 行为

    当你的混合式沉浸空间不需要 用户感知真实的周围环境时 就可以这样配置

    我很喜欢为 App 添加的这些道具 但我知道用户在创建新场景时 肯定也会想导入自己的模型 他们可能会在自己最喜欢的 macOS App 中创建这些模型

    为了支持他们直接在 Mac 上使用这些模型 我将 App 带到了 macOS 并保留了相同的舞台创建功能

    如果用户能直接 在 Vision Pro 上以沉浸式空间 预览这些场景 而无需从 macOS 手动传输舞台 是不是会更高效?

    visionOS 26 和 macOS Tahoe 引入了 RemoteImmersiveSpaces 正好能实现这一点 借助远程沉浸式空间 你可以使用 CompositorLayer 结合 Metal 利用 Mac 上的 App 代码和资源 来渲染内容

    并将它作为沉浸式体验显示在 Vision Pro 上

    我们来看看它在我的 App 中 是如何实际运行的

    在我的 Mac App 上 我用 Metal 构建了一个新的沉浸式空间 并添加了一个 “Preview in Vision Pro”按钮

    点按这个按钮后 会让我 选择一个目标 Vision Pro 设备

    然后我在 Vision Pro 上接受连接 请求

    就这样 ImmersiSpace 被打开了 我可以在机器人最新的剧目中 看到我刚添加的道具

    我是通过添加一个包含 CompositorLayer 的 RemoteImmersiveSpace 场景 实现这一点的

    这个场景会在 visionOS 上呈现 而我的其他场景 比如主舞台 依然会直接 显示在 Mac 上

    要进一步了解如何将 CompositorLayer 和 ARKitSession 适配到远程 Vision Pro 设备 欢迎观看“用于打造沉浸式 App 的 Metal 渲染的新功能”

    在远程沉浸式空间中使用 CompositorLayer 可以充分发挥 Metal 的渲染能力 打造强大的沉浸式体验

    但 CompositorLayer 本身不是 一个 View 因此无法用于 需要视图的上下文 比如 ImmersiveContent

    以往 这意味着无法在 CompositorLayer 中使用 环境变量或视图修饰符

    而在 visionOS 26 中 全新引入了 CompositorContent 构建器类型 它让你可以在 CompositorLayer 中充分发挥 SwiftUI 的能力

    现在 你可以像使用 SwiftUI 视图那样 访问环境变量、添加修饰符 甚至使用状态变量

    CompositorContent 带来了 大量实用的环境变量 比如 scenePhase 和 openWindow 还有一些修饰符 比如 onImmersionChange 和 onWorldRecenter

    这些功能让 CompositorLayer 无论是在远程沉浸式空间中 还是在直接运行于 visionOS 的 本地场景中 都变得更加强大

    将我的 App 升级为使用 CompositorContent 也让我重新审视了可用于沉浸式 空间的一些修饰符 并探索它们在我 App 中的应用方式

    这就是沉浸式空间的最新功能: 世界重新定位事件 沉浸样式的新自定功能 通过 RemoteImmersiveSpace 从 Mac 实现沉浸式空间 以及新的 CompositorContent

    有了这些新功能 我的 App 看起来已经非常出色 事实上 我现在甚至想把这些酷炫的 空间容器体验 扩展到更多 App 中

    不过 我的一些 App 是用 UIKit 构建的 而 UIKit 本身并不支持空间容器和 沉浸式空间 但现在 有了场景桥接 这也变得可行了

    场景桥接能让你在现有的 UIKit App 中 加入 SwiftUI 的空间容器 和沉浸式空间功能 让 App 实现从二维向三维的跃迁

    以 Safari 浏览器为例 它使用的是 SwiftUI 视图 但却是使用 UIKit 生命周期构建的

    在 Safari 浏览器的全新空间浏览 功能中 就充分运用了场景桥接

    让我们也来看看该如何实现

    要在 UIKit App 中桥接一个 SwiftUI 场景 我首先创建一个扩展自 UIHostingSceneDelegate 的类

    借助这个类型 我可以在 rootScene 属性中 使用熟悉的场景主体语法来 声明 SwiftUI 场景

    现在 我可以像请求其他 UIKit 场景一样 通过创建 UISceneSessionActivationRequest 来请求这个场景

    在这个请求中 我传入 hostingDelegateClass 其中声明了我的场景 以及我想打开的场景 ID

    最后 调用 activateSceneSession 来发送这个请求即可

    你也可以在 configurationForConnecting 中 设置 hostingDelegateClass 以响应外部事件

    这个 API 也提供了对应的 AppKit API 可将 SwiftUI 场景桥接到现有的 macOS AppKit App 中

    现在 我的 App 已充分利用 visionOS 26 的新能力 例如固定到位、吸附表面、 以及从 Mac 远程打开等功能 我迫不及待想把它展示给朋友们看了

    现在轮到你来看看自己的 App 了 检查你的场景 确保充分利用了 位置锁定与状态恢复

    通过吸附与裁剪边距 让场景更好地适应用户周围的环境

    并通过远程沉浸式空间 将你的 macOS App 内容 带入 Vision Pro 的沉浸式体验中

    帷幕落下 但在我们的 App 中 演出仍将继续 一幕接一幕 感谢观看

    • 4:10 - Disabling restoration

      // Disabling restoration
      
      WindowGroup("Tools", id: "tools") {
          ToolsView()
      }
      .restorationBehavior(.disabled)
    • 4:36 - Disabling restoration in UIKit

      // Disabling restoration
      
      windowScene.destructionConditions = [
          .systemDisconnection
      ]
    • 5:02 - Specifying launch window

      // Specifying launch window
      
      @AppStorage("isFirstLaunch") private var isFirstLaunch = true
      
      var body: some Scene {
          WindowGroup("Stage Selection", id: "selection") {
              SelectionView()
          }
      
          WindowGroup("Welcome", id: "welcome") {
              WelcomeView()
                  .onAppear {
                      isFirstLaunch = false
                  }
          }
          .defaultLaunchBehavior(isFirstLaunch ? .presented : .automatic)
      
          // ...
      }
    • 6:39 - "suppressed" behavior

      // "suppressed" behavior
      
      WindowGroup("Tools", id: "tools") {
          ToolsView()
      }
      .restorationBehavior(.disabled)
      .defaultLaunchBehavior(.suppressed)
    • 7:44 - Unique window

      // Unique window
      
      @AppStorage("isFirstLaunch") private var isFirstLaunch = true
      
      var body: some Scene {
          // ...
      
          Window("Welcome", id: "welcome") {
              WelcomeView()
                  .onAppear {
                      isFirstLaunch = false
                  }
          }
          .defaultLaunchBehavior(isFirstLaunch ? .presented : .automatic)
      
          WindowGroup("Main Stage", id: "main") {
              StageView()
          }
      
          // ...
      }
    • 10:24 - Surface snapping

      // Surface snapping
      
      @Environment(\.surfaceSnappingInfo) private var snappingInfo
      @State private var hidePlatform = false
      
      var body: some View { 
          RealityView { /* ... */ }
          .onChange(of: snappingInfo) {
              if snappingInfo.isSnapped &&
                  SurfaceSnappingInfo.authorizationStatus == .authorized
              {
                  switch snappingInfo.classification {
                      case .table:
                          hidePlatform = true
                      default:
                          hidePlatform = false
                  }
              }
          }
      }
    • 14:41 - Clipping margins

      // Clipping margins
      
      @Environment(\.windowClippingMargins) private var windowMargins
      @PhysicalMetric(from: .meters) private var pointsPerMeter = 1
      
      var body: some View {
          RealityView { content in
              // ...
              waterfall = createWaterfallEntity()
              content.add(waterfall)
          } update: { content in
              waterfall.scale.y = Float(min(
                  windowMargins.bottom / pointsPerMeter,
                  maxWaterfallHeight))
              // ...
          }
          .preferredWindowClippingMargins(.bottom, maxWaterfallHeight * pointsPerMeter)
      }
    • 16:44 - World recenter

      // World recenter
      
      var body: some View {
          RealityView { content in
              // ...
          }
          .onWorldRecenter {
              recomputePositions()
          }
      }
    • 17:58 - Progressive immersion style

      // Progressive immersion style
      
      @State private var selectedStyle: ImmersionStyle = .progressive
      
      var body: some Scene {
          ImmersiveSpace(id: "space") {
              ImmersiveView()
          }
          .immersionStyle(
              selection: $selectedStyle,
              in: .progressive(aspectRatio: .portrait))
      }
    • 18:37 - Mixed immersion style

      // Mixed immersion style
      
      @State private var selectedStyle: ImmersionStyle = .progressive
      
      var body: some Scene {
          ImmersiveSpace(id: "space") {
              ImmersiveView()
          }
          .immersionStyle(selection: $selectedStyle, in: .mixed)
          .immersiveEnvironmentBehavior(.coexist)
      }
    • 20:14 - Remote immersive space

      // Remote immersive space
      
      // Presented on visionOS
      RemoteImmersiveSpace(id: "preview-space") {
          CompositorLayer(configuration: config) { /* ... */ }
      }
      
      // Presented on macOS
      WindowGroup("Main Stage", id: "main") {
          StageView()
      }
    • 20:48 - 'CompositorLayer' is a 'CompositorContent'

      // 'CompositorLayer' is a 'CompositorContent'
      
      struct ImmersiveContent: CompositorContent {
          @Environment(\.scenePhase) private var scenePhase
      
          var body: some CompositorContent {
              CompositorLayer { renderer in
                  // ...
              }
              .onImmersionChange { oldImmersion, newImmersion in
                  // ...
              }
          }
      }
    • 23:00 - Scene bridging

      // Scene bridging
      
      import UIKit
      import SwiftUI
      
      // Declare the scenes
      class MyHostingSceneDelegate: NSObject, UIHostingSceneDelegate {
          static var rootScene: some Scene {
              WindowGroup(id: "my-volume") {
                  ContentView()
              }
              .windowStyle(.volumetric)
          }
      }
      
      // Create a request for the scene
      let requestWithId = UISceneSessionActivationRequest(
          hostingDelegateClass: MyHostingSceneDelegate.self, id: "my-volume")!
      
      // Send a request
      UIApplication.shared.activateSceneSession(for: requestWithId)
    • 0:00 - 简介
    • 在 visionOS 26 中,你可以使用全新的场景、窗口、空间容器和沉浸式空间 API,打造更具动态性和交互性的 App。新功能包括生命周期 API、视体增强功能、支持在 Apple Vision Pro 上预览的“RemoteImmersiveSpace”,以及用于 UIKit App 的场景桥接 API。

    • 2:11 - 启动或固定位置
    • visionOS 26 中新增的 API 可帮助你管理 App 启动和场景恢复,打造更具沉浸感的体验。用户现在可以将窗口、空间容器和小组件锁定至特定房间,让虚拟内容持久驻留于物理环境中。 当用户重返对应房间时,系统会自动恢复被锁定的窗口,但你可以使用“restorationBehavior(.disabled)”修饰符来禁用瞬态元素 (如欢迎屏幕或上下文相关 UI) 的恢复。 你还能通过“defaultLaunchBehavior”修饰符自定义 App 的启动行为,根据 App 状态动态选择要展示的窗口。 对于不能被复制的唯一窗口,现在可使用 Window API 来避免重复创建游戏窗口或视频通话等关键界面。

    • 8:15 - 视体增强功能
    • 现在,空间容器迎来了几项关键增强功能。通过“SurfaceSnappingInfo”API,你可以监控窗口和空间容器何时吸附到物理表面 (如墙壁、桌面)。由于你可以根据吸附状态调整场景,例如隐藏平台或调整道具,因此这项功能可提供更具沉浸感的体验。获得用户授权后,ARKit 还能向 App 提供被吸附表面的详细信息。 这次更新还扩展了内容呈现能力。现在空间容器、装饰元素和 RealityKit 中的内容均可作为呈现源,系统会通过特殊的视觉处理技术确保这些内容在 3D 场景中始终保持可见。使用“presentationBreakthroughEffect”修饰符可以自定义视觉处理。 除此之外,新增的 Clipping Margins API 允许在空间容器的场景边界外渲染非交互式内容,增强瀑布或云朵等视觉效果,同时确保主要内容区域不受干扰。读取“windowClippingMargins”环境变量,可以查看系统是否已授予外边距。

    • 15:58 - 沉浸式空间
    • 现在,你可以响应世界重新定位事件,让用户将 App 的体验重新定位到他们周围。使用“onWorldRecent”视图修饰符监听这一事件,并根据新的坐标系重新计算并保存位置。 visionOS 26 还为多种沉浸样式引入了新的自定选项。渐进式沉浸样式现在支持纵向宽高比,可实现垂直场景体验,同时提升大量运动内容的舒适感。混合沉浸样式现在允许内容与系统环境无缝融合,打造更具沉浸感的场景。通过“immersiveEnvironmentBehavior”场景修饰符并选择“coexist”行为,即可启用这一混合效果。 现在,你可以通过“RemoteImmersiveSpaces”将 App 移植至 macOS,还可以直接在 Apple Vision Pro 上预览作为沉浸式空间的场景。这项功能可以显著加快迭代,提高协作效率。借助“CompositorLayer”,你可以在 Mac 上使用 Metal 渲染内容,并将内容显示在 Apple Vision Pro 中。 引入“CompositorContent”构建器类型意味着你可以将 SwiftUI 的全部功能与“CompositorLayer”结合使用,让创建与管理本地和远程的沉浸式体验更加便捷,包括访问环境变量、添加修饰符以及使用状态变量。

    • 22:16 - Scene Bridging
    • 借助 visionOS 26 中的场景桥接功能,你可以将 SwiftUI 空间容器和沉浸式空间添加到现有的 UIKit App 中。通过扩展“UIHostingSceneDelegate”,你可以创建 SwiftUI 场景并使用“UISceneSessionActivationRequest”请求调用这些场景,这使得 Safari 浏览器等 App 能够实现“空间浏览”功能,同时让其他 App 也能充分利用 visionOS 的新功能。

    • 24:01 - 后续步骤
    • 示例 App 支持用户创建能够固定到位、吸附表面以及能从 Mac 远程打开的场景。查看自己的 App,确保充分利用了这些新功能。

Developer Footer

  • 视频
  • WWDC25
  • 借助 SwiftUI 在 visionOS 中设置场景
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则