大多数浏览器和
Developer App 均支持流媒体播放。
-
使用 Xcode 预览构建编程 UI
了解如何在 Xcode 15 上使用 #Preview 宏快速迭代以 SwiftUI、UIKit 或 AppKit 编写的 UI 代码。探索与画布中的视图交互的独特工作流程拼贴,了解如何同时查看 UI 的多个变体,并了解如何在几秒钟内浏览小组件的时间线,以测试条目之间的过渡。我们还将向你展示如何向资料库添加预览、提供示例资源以及在物理设备中预览视图,以便利用其功能和现有数据。
章节
- 1:26 - What are previews
- 3:42 - Preview syntax basics
- 4:44 - Writing SwiftUI previews
- 5:50 - Writing UIKit & AppKit previews
- 6:08 - Demo: Putting writing previews into action
- 11:39 - Writing previews for widgets
- 15:58 - Previewing in library targets
- 20:28 - Passing sample data into previews
- 22:08 - Previewing on devices for full fidelity and access to data
- 25:50 - Wrap-up
资源
相关视频
WWDC23
-
下载
♪ ♪
Kevin Cathey:大家好 我是 Kevin 负责 Previews 的工作 软件开发 尤其是 App 开发 是一个不断迭代 且富有创造力的过程 你肯定希望 能以最快的方式测试你的代码 并亲身体验你所创造的作品 这正是我们开发预览的原因 为你提供即时的视觉反馈 让你专注于创造性的工作 此外 预览的使用方式很灵活 可以在 App 的整个开发过程中使用 适用于不同类型的 视图、数据和设备 无论你是初次接触预览 还是已经使用了一段时间 我都希望能帮助你充分利用它 本讲座分为三个部分 首先 我们会了解预览的概念 了解其工作原理 以及与项目中其他代码的关系 对你会有所帮助 其次 有两种不同的方式 可为你的预览提供内容 即视图和小组件 我会向你展示如何编写预览 以及在 Xcode 中的一些独特工作流程 最后 当你开始在项目中使用预览时 可能会遇到一些常见的场景或问题 我会为你提供一些技巧和诀窍 帮助你在项目中更好地利用预览 我们开始吧 预览到底是什么呢? 预览是用于创建 和配置视图的一小段代码 编写在源代码文件的顶部 不嵌套在任何类型或函数内部 而且可以非常简单 你可以使用 #Preview 宏 返回一个视图 预览与 App 中的 其他代码和资源一起编译 预览能够访问这些符号和资源 因此 它具有极高的灵活性 你可以根据需要 来为 App 中的视图设置预览 并在 Xcode 的画布中 即时显示出来 预览也能助力快速迭代 当你编辑 项目中的 Swift 代码时 Xcode 会自动执行两项操作 它先会检查你所做的更改 并重新编译最少量的代码 然后重新运行你的预览 因此 你可以 专注于编写和迭代代码 而 Xcode 会自动处理构建、运行 和更新预览 定义了预览后 Xcode 便可以 自动在不同的上下文中运行该预览 你不需要再额外编写任何代码 好比你可以在深色模式下 或不同的类型尺寸和方向中进行测试 虽然这个类比不完全贴切 但把预览类比为测试 可能有助于理解 与测试类似 预览在真实项目中运行真实的代码 不是模拟或解释代码 也就是说 你知道正在测试和预览的内容 就是 App 的用户会体验的内容 其次 在编写测试 和预览中投入时间精力 会帮你提高开发效率 投入小 但效果好 第三 你可以测试 和预览 App 的不同层面 例如 通过测试 你可以进行高级 UI 测试 验证 App 功能的重要部分 并且可以进行更小的单元测试 测试各个组件 类似地 你可以为涵盖 App 大部分内容的视图创建预览 也可以创建 可显示单个叶视图的预览 以上是预览工作原理的简要介绍 接下来 我们来了解 如何编写预览以及可预览的内容类型 无论预览什么 每个定义的预览 都具有相同的基本结构 包括三个部分 先从源文件顶部的 Preview 宏初始化定式开始 然后 返回一个 或多个内容的尾随闭包 你可以在这里为想要预览的具体场景 配置 UI 这就是制作预览的步骤 当然 你还可以为预览本身 配置更多的灵活性 你可以给它命名 并根据不同的预览内容 还可以向初始化定式 传递额外的配置 我们会看到几个示例 现在 来了解一下 可以预览的内容类型 主要有两种内容:视图和小组件 视图可来自 SwiftUI、 UIKit 或 AppKit 对于 SwiftUI 只需返回你正在处理的视图 但不是仅仅传递正在处理的视图 你可以将其放置在 需要的其他视图中 这样做的好处是 你可以在 更广泛的上下文中处理视图 例如 始终预期在列表中的视图
此位置可以附加 提供环境数据的修饰符 以满足视图的预览需求 预览与 App 的 顶层定义的场景类似 场景是 App 的入口点 我们设置数据 并通过视图来传递场景 预览服务于相同的目的 因此 你可以使用预览 来设置数据和资源 然后将它们 传递给你正在预览的视图 在配置预览时 你可以为其命名 像 SwiftUI 这样的 基于视图的预览 支持将一个或多个配置特征 作为可变参数列表进行传递 例如 你可以为要预览的设备 设置起始方向 UIKit 和 AppKit 中的 API 的形式是相同的 不用 SwiftUI 视图 只需创建一个视图控制器 并根据需要进行配置 除了视图控制器 你还可以直接预览 UIView 或 NSView 根据你正在构建的内容 可以设置不同的灵活性 我会向你展示我们刚才说到的内容 以便你了解如何开始使用预览 以及一些帮助灵活设置预览的工具 我正在编写 一个制作图像拼贴的 App 可以选择照片 和布局 并添加滤镜 我们进入 Xcode 去探索预览画布的功能 我已经在编写视图 来给图像添加滤镜 我需要预览来帮助我迭代此视图 首先 我会确保画布模式已启用 方法是转到编辑器的右上角 并点击选项菜单 对于新项目 画布模式会默认启动 但如果是现有项目 可能需要手动开启 但即使启用了画布模式 若没有在文件中定义预览 画布仍然是隐藏的 我们现在来添加一个预览 当我开始输入#Preview 时 Xcode 会为我提供预览建议 如果接受了自动完成 Xcode 会构建和运行我的预览 我的视图会出现在画布中 我可以用 三种不同的模式来处理视图 这些模式在画布的左下角显示 第一个模式是默认模式 叫实时或交互模式 大部分情况下 我都使用这个模式 因为我可以在画布中 与视图进行交互 比如拖动这些滑块
我还可以测试动画 并调用和响应异步代码 第二个模式是选取或静态模式
此模式会对我的视图进行快照 可以让我在画布中与元素进行交互 点击一个视图会 在源代码编辑器中突出显示 生成它的代码行 如果双击某些文本视图 比如这个标签 焦点会移动到源代码编辑器中 我便可以快速进行更改 晕影这个标签更简洁 我们来了解一下环境 也就是预览环境 画布是在浅色模式下显示预览 但如果我想在 深色模式下查看预览呢? 可以修改代码来设置颜色方案 我通常只是想 在深色模式下快速检查一下 可能还会进行一些微调 我会使用画布中的 Device Settings 弹出窗口 在底部工具栏中 点击控件图标打开设置 现在 可以启用深色模式 或设置具体的动态类型大小 但如果我想同时看到视图 在两种颜色方案下的效果呢? 对于这个问题 我会使用 预览的第三种模式:变体模式
当我点击画布底部的变体模式时 可以选择想要查看的所有设备设置 比如颜色方案 或所有动态类型大小 我可以通过点击来查看单个变体 还可以逐一浏览变体 嗯 当动态类型较大时 视图就散乱了 对吧? 我们来解决一下 我不使用 VStack 而是使用 Form 因为 Form 很适合应用于多组控件 当控件放置在 Section 中时 表单的外观效果会更好 我们把每个 HStack 设为一个 Section 我可以通过利用多重光标编辑 在所有 HStack 实例中 做出这些更改 我选择第一个 HStack 然后按 Command-Option-E 键 找到并插入光标 到每个 HStack 实例 我会把每个 HStack 更改为 Section
我还想为每个 Section 添加一个节头 这可以通过第二个尾随闭包来提供 按下方向键并添加一个尾随闭包
让我们使用已经存在的标签 作为这些节头的内容 按上方向键移动到 Label 按 Command-Option-右大括号键 把 Label 移到节头中 这样 视图看起来就好多了 这些功能同样适用于 AppKit 和 UIKit 的 视图和视图控制器 我会切换到使用 CoreImage 渲染滤镜的视图控制器 并将画布切换回实时模式 我为此视图控制器创建了一个预览 看起来 与 SwiftUI 的预览非常相似 在预览宏中 我创建了一个视图控制器 并向其传递了一个示例图像 但我想测试一下应用了滤镜的图像 我会添加代码 来向视图控制器传递一个滤镜 光晕和晕影滤镜永远不会过时 除了配置视图控制器 还可以配置预览 任何预览都可以 有一个名称作为第一个参数 对于像 SwiftUI 和 UIKit 这样的视图预览 可以在名称之后的可变参数 列表中添加一个或多个特征 例如 我可以将预览 设置为在横屏模式下启动 以上就是编写视图预览的简单介绍
预览的第二个主要类别是小组件 小组件预览 真正展示了预览速度之快 我们可以预览两种类型的小组件 第一种是使用时间轴提供程序 生成单个条目的小组件 在 Xcode 中 你可以预览 完整的时间轴提供程序 或者可以直接在预览中 创建自己的时间轴条目 我们去 Xcode 中 看一下这两种情况的示例 我的图像拼贴 App 有一个有时间轴提供程序的小组件 每小时展示一次随机生成的拼贴 对于我的时间轴提供程序 我会创建一个预览 包括以下三个部分: 第一个是我想要预览的小组件 第二个是时间轴提供程序 第三个是用于预览的小组件系列
只需要少量的代码 就能在 Xcode 中 为我提供出色的工作流程 虽然此小组件 每小时构建一个随机的拼贴 但我不必等一个小时 才能查看时间轴中的每个条目 预览会给每个时间轴条目 拍快照 并将其显示在画布上 我可以通过单击 或使用方向键进行切换 当我这样做时 Xcode 会与我的小组件通信 并以动画形式 显示这些条目之间的过渡 让我不仅能够 发现用户界面的问题 还能发现时间轴不同点之间的更改 就像这里的第 8 个 和第 9 个条目之间的更改 这里的动画效果不太好 只是一个淡入淡出效果 我想修复这种情况 但是我的时间轴提供程序是随机的 所以 我不知道 测试时是否会再次遇到这种情况 特定条目的时间轴 在这里就能派上用场了 我可以创建一个 精确的场景进行迭代 我会在预览中把 timelineProvider 改为 timeline 并且不再返回时间轴提供程序 而是返回两个复制了 我要修复的情况的条目 但是 我用来修复此过渡的代码 存在于另一个文件中 我不希望在切换页面时 丢失这个预览 还好我可以使用固定功能 将预览保留在画布中 在画布的左上角点击固定按钮 即使导航到另一个文件 它也会让预览保持活动状态
这是绘制拼贴并包含过渡的视图 为了能专注于解决问题 在画布中 我可以按下时间轴中的播放按钮 和循环按钮 当我修复代码时 Xcode 会一直重播此过渡 噢 问题出现在这里 当拼贴由行组成时 附加了一个过渡 但是当拼贴由列组成时 却没有附加过渡 我可以复制并粘贴过渡 这样就好多了 但动画是从右侧边缘推出的 我觉得从底部推出比较好 这样就好了 通过预览 我不仅可以利用时间轴提供程序 迅速迭代用户界面 还能使用特定事件来精调动画效果 让构建和迭代 UI 更快、更有趣
这些相同小组件的工作流程也适用于 第二类可以预览的小组件:实时活动 API 几乎相同 但是不再提供 时间轴提供程序和条目 而是提供一组实时活动属性和状态 我们来看一个示例 首先 在初始化定式中 传递要使用的属性 然后 为这些属性传递内容状态 例如 如果你正在构建 一个用于订购披萨的小组件 可以为该披萨的烘焙和配送 提供一组自定义状态 并测试 所有这些状态之间的动画效果 我仅仅简单地介绍了 使用小组件预览可做的事 请观看讲座“为小组件注入活力” 进一步了解相关信息 接下来 我们会进入 本讲座的最后部分 我将介绍如何在项目中 充分利用编写预览的功能 我们会了解到 涉及项目设置、提供数据 以及利用设备功能的 三种不同的场景 我先来介绍一下 如何在资料库目标中预览内容 其中包括框架、 Swift 包或动态库 你可能会在很多情况下使用资料库 例如 你可能会使用资料库 来模块化项目 或正在开发一个 要分发给别人的资料库 预览在这些目标中运行得很好 而且你可以利用资料库目标 在任何项目中 进一步使用预览 利用资料库的第一步是了解什么是 预览用于运行代码的可执行文件 预览需要一个可执行文件 可能是 App 或小组件 用于启动和渲染预览 通常情况下是使用 App 但如果没有 App 该怎么办? 预览会根据三个要素 来确定要使用哪个可执行文件 第一个 是你要处理的源文件 其次 是这些文件所在的目标 以及这些目标的所有依赖项 最后 预览会将这些目标依赖项 与你选择的方案中的目标 进行交集计算 预览只会选择 处于活动方案中的 App 我们来看几个示例 在最简单的情况下 你可能正在处理 一个属于 App 目标的单个源文件 那这就是我们用于预览的 App 但是 如果该源文件 放在两个目标中呢? 例如 App 的试用版和完整版 这就体现了方案的重要性 预览只会使用活动方案中的 App 再看看另一个示例: 假设你打开了两个 Swift 文件 每个文件都属于一个包 这些包可能会导入另一个包 然后 所有的包都会导入一个 App 我们会从这些文件开始向上遍历 找到最上层的公共可执行文件 有鉴于此 现在我们 回到我们之前提出的问题: 如果没有 App 该怎么办? 在这种情况下 预览会为你 自动创建一个名为 XCPreviewAgent 的 App 来加载你的资料库 这一切都会自动进行 但了解这个过程的工作原理 以及这个过程的名称 有助于你了解代码的运行位置 例如 如果 XCPreviewAgent 出现崩溃报告 你就知道这是在你的代码中发生的 并且可以找到问题所在 你可以利用资料库目标 通过至少两种方式 在你的项目中进一步使用预览 我们可能要花很多时间 来讨论每个方式 但我在这里只想简要提一下 首先 如果把 App 模块化为资料库 你可以创建较小的方案 来获得更高质量的构建时间 或者只关注项目的某一部分 即使使用的是 包含一部分目标的较小方案 你仍然可以 充分利用预览的全部功能 其次 如果你将代码模块化为资料库 可能有些视图 需要你的 App 目标提供的 授权或 Info.plist 键 还可以通过创建一个专门用于预览的 小型 App 来预览这些视图 我们看看如何操作 假设我正在创建 一个使用照片库的视图 需要一个特定的 Info.plist 键 并且我已经将该视图 放在一个资料库中 如 SamplePhotoLibraryUtilities
我可以创建一个新的 App 目标 添加我需要的功能 然后使用相应的功能进行预览 在本例中 我需要 添加一个 Info.plist 键 因此 我会进入构建设置 过滤照片库使用字符串 并进行设置 接下来 要确保 包含我正在处理的视图的资料库 会被嵌入到我的 App 中 使用构建阶段选项卡 将它添加为目标依赖项 并使用复制文件阶段进行嵌入 我可以选择只包含 此预览 App 和我的资料库的方案 当我预览视图时 会使用到刚刚为预览创建的 App 并且所有正确的 Info.plist 键将会就位 这样一来 我就能够利用 短时间内构建的小方案 同时仍能预览 我正在处理的所有视图 接下来 我们来看看 如何把数据和资源导入到你的预览中 我在之前的演示中 悄悄用过这个功能 现在 我想来回顾一下我的操作 让我们回到之前呈现滤镜的 视图控制器 我在配置预览时 传入了一个示例图像 此图像来自我的项目中的资源目录 如果我显示项目导航器 资源目录就会位于此处 在预览内容文件夹内 这些图像在开发过程中非常有用 可以帮我测试不同的场景 无需为每个设备配置照片 但是我不想将这些图像 包含在我的 App 中 可以通过一个名为 开发资源的功能来避免这种情况 这些是我在构建设置中 配置的项目中的文件夹 当我提交到 App Store 时 这些文件夹中的内容 都会从我的 App 中删除 包括资源目录 或你在预览时使用到的资源 我们将此预览内容文件夹 添加为开发资源路径
在项目设置中 转到构建设置标签页 然后就可以过滤开发资源了 双击以进行编辑后 我可以手动键入路径 或者将预览内容文件夹 拖放到弹出窗口中
添加后 在我提交到 App Store 时 该路径会从我的 App 中删除 当你创建新项目或 App 目标时 系统会自动设置开发资源路径 但你也可以添加其他路径 或将其添加到 其他目标类型或现有项目中 这个演示突出了如何使用 开发资源来将资源添加到项目中 从而为预览提供资资源 如果你想在所有设备 和团队之间共享所有这些资源 这种方式非常有效 但如果你想快速启动和运行 还有另一种提供数据和图像的方法 我们很多人的设备上 都拥有资源和数据 预览可以利用这些资产和数据 Xcode 的模拟器功能非常强大 可为大多数开发提供良好基础 预览在模拟器中效果很好 也可以在实体设备上 起到很好的效果 由于以下原因 你会希望 在最终发布 App 的设备上 进行预览 例如 你可能 想要访问摄像头或传感器 另一个原因是你的设备上可能已经 有很多真实数据 如照片或文件 现在 我来向你展示 如何利用设备数据
我正在处理的另一个视图中 有一个按钮 通过此按钮可以从 iCloud 照片库中选择照片 然后 选择一个布局 来创建新的拼贴画 我想以在其他视图上 迭代的相同方式测试一下 但我需要用到拥有大量照片的设备 我会通过底部画布中的 预览设备选择器 更改要用于预览的设备 我们来深入了解一下各种选项 大多数情况下 你可以使用自动模式 该模式会跟踪 你选择的运行目的地的设备系列 菜单的最底端是“更多”子菜单 列出了你在设备窗口中 添加的所有模拟器设备 你可以选择所需的具体型号 可能有时 你想要根据设备功能来选择设备 在菜单的中间部分 按常见功能列出了设备 这样你就不必记住哪个型号 有触控 ID 等功能 我想使用旁边的这台设备 这样我就可以 访问我的图库中的大量照片
预览设备选择器还包括 与我的 Mac 连接的任何设备 当我选择其中一个连接的设备时 Xcode 会仅为该设备构建和预览 并完全绕过模拟器 就这样 我的视图 就在真实设备上运行了 虽然是在我的设备上 但我可以使用 此前讨论过的预览功能 我仍然可以使用画布的所有模式 还可以进行设备设置 例如 这在深色模式下是什么样子?
如果更新代码 我的设备上立即会有相应显示 此视图需要一个导航标题 因此 我会在代码中添加 navigationTitle 然后自定义标题 并立即在设备上查看
真是神速! 现在 我准备用手机上的所有图片 来测试我的照片库集成 我会点击“从照片添加” 选择照片 这只松鼠太可爱了 然后点击“添加” 此视图运行得很不错 我的照片出现在布局选择器中 我可以快速试用不同的布局 我喜欢这个 在 Xcode 中进行编辑 并在手机上查看鲜活的视图可真有趣 以上就是在项目中 使用预览的三个技巧 最后 总结一下: 预览 API 让你能以灵活的方式 为整个 App 和所有 Apple 平台 定义 UI 预览 你可以使用 SwiftUI、UIKit、 AppKit 和多种类型的小组件 预览功能还可以帮你 灵活地配置预览 以符合你的切实需求 你可以传递示例数据和资源 通过代码设置环境 并利用 Xcode 的功能 来测试不同的设备设置 而且预览还可以让你根据需要 在不同设备上进行预览 包括在画布上 便捷地使用模拟器进行预览、 使用实体设备进行预览 从而获得最高的保真度 以及访问数据和照片 但无论你选择什么设备 都可以使用所有预览功能 最后 如果将 App 的 一部分或是全部模块化为资料库 你就可以在 Xcode 中 创建方案 来获得高质量的构建时间 并专注于你正在处理的内容 预览可激发你的无限创造力 感谢你的观看
-
-
1:30 - Basic preview
#Preview { MyView() }
-
5:05 - Previewing a SwiftUI view in a list
#Preview { List { CollageView(layout: .twoByTwoGrid) } .environment(CollageLayoutStore.sample) }
-
5:37 - Previews can have a name and configuration traits
#Preview(“2x2 Grid”, traits: .landscapeLeft) { List { CollageView(layout: .twoByTwoGrid) } .environment(CollageLayoutStore.sample) }
-
5:58 - Previewing UIKit view controllers and views
#Preview { var controller = SavedCollagesController() controller.dataSource = CollagesDataStore.sample controller.layoutMode = .grid return controller } #Preview(“Filter View”) { var view = CollageFilterDisplayView() view.filter = .bloom(amount: 15.0) view.imageData = … return view }
-
7:08 - Xcode can help suggest a preview
#Preview { FilterEditor() }
-
11:30 - Setting a UIKit preview to start in landscape
#Preview("All Filters", traits: .landscapeLeft) { let viewController = FilterRenderingViewController() if let image = UIImage(named: "sample-001")?.cgImage { viewController.imageData = image } viewController.filter = Filter( bloomAmount: 1.0, vignetteAmount: 1.0, saturationAmount: 0.5 ) return viewController }
-
12:20 - Previewing a small widget with a timeline provider
#Preview(as: .systemSmall) { FrameWidget() } timelineProvider: { RandomCollageProvider() }
-
25:07 - Updating the navigation title while previewing on device
.navigationTitle(“Add Collage”)
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。