开场白

您好,欢迎来到WWDC。欢迎使用SwiftUI中的App Essentials。我叫Matt Ricketson,我在SwiftUI上工作。稍后,我的同事Jeff将加入我的行列。去年,我们推出了SwiftUI,这是一种强大的新方法,可以在所有Apple平台上构建出色的用户界面。我们使用视图构建用户界面,SwiftUI提供了一套API,用于修改视图并将它们组合在一起。今年,我们将使用用于声明场景和应用程序的新API扩展框架,这是对您可以使用SwiftUI进行构建的重大扩展。最重要的是,您现在仅可以使用SwiftUI构建整个应用程序。在本节中,我们将介绍这些新的API,并说明视图,场景和应用程序如何协同工作。

接下来,我们将深入介绍SwiftUI的场景架构,并展示如何自定义应用程序中的场景。最后,我们将简要概述可用于自定义应用程序的各种API,以及在何处可以了解更多信息。现在,让我们从讨论视图开始。如果您以前使用过SwiftUI,那么您已经熟悉了。


View视图很重要

视图很重要,因为每个视图都定义了一部分用户界面。当您查看应用程序时,所看到的都是视图。单个图像和一段文字就是视图。容纳它们的容器也是视图。实际上,您在屏幕上看到的每个像素都以某种方式由视图定义。但并非所有视图都属于同一应用程序,因为应用程序无法完全控制整个屏幕。而是由平台控制如何显示应用程序,以显示不同区域中的应用程序片段。在SwiftUI中,我们将这些不同的区域称为场景。窗口是在屏幕上显示场景内容的最常见方式。某些平台(如iPadOS)可以并排显示多个窗口。其他平台(例如iOS,watchOS和tvOS)更喜欢为每个应用程序仅显示一个全屏窗口。

在这种情况下,我们看到了一组相关窗口,其中每个窗口都是不同场景内容的体现。macOS还允许您将相关窗口收集到单个选项卡式窗口中。在这种情况下,我们的场景将显示为单独的选项卡。此共享窗口也由其自己的场景表示,充当与每个选项卡关联的子场景的容器。这些场景集合构成了应用程序的全部内容。应用程序,场景和视图一起构成了统一的所有权层次结构。正如我们前面提到的,视图是呈现您在屏幕上看到的所有内容的基本构建块,并且可以组合在一起以形成更复杂的用户界面。视图构成了场景的内容,从而使平台可以独立显示它们。像视图一样 这些场景也可以组合在一起以形成更复杂的场景,就像我们在前面看到的带选项卡的窗口示例中一样。最后,所有这些场景构成了应用程序的内容。现在,我们了解了应用程序,场景和视图如何协同工作,让我们看一下它在SwiftUI代码中的作用。在这里,我们看到了我在SwiftUI中编写的一个基本应用程序,可帮助我跟踪在读书俱乐部阅读的书籍。如您所见,SwiftUI中的应用程序具有简洁的声明。意味着像这样的基本应用程序只能容纳少数几行代码。没有这些额外的样板,您可以立即专注于应用程序特有的代码。在这种情况下,我们使用称为ReadingListViewer的视图定义了应用程序的实际界面。ReadingListViewer是我单独构建的自定义视图,使我可以浏览阅读列表。我们的ReadingListViewer包含在称为WindowGroup的场景中。WindowGroup场景管理我们的ReadingListViewer将渲染到的窗口。它还可以在支持这些功能的平台上创建其他窗口或同一窗口内的新选项卡。Jeff将在稍后的演讲中详细解释WindowGroup的工作原理。我们的WindowGroup场景包含在由符合应用协议的自定义结构表示的应用中。您会注意到,代码的结构与我们之前看到的所有权层次结构匹配。该应用程序包含场景,而场景包含视图。或支持这些功能的平台上同一窗口中的新标签。Jeff将在稍后的演讲中详细解释WindowGroup的工作原理。我们的WindowGroup场景包含在由符合应用协议的自定义结构表示的应用中。您会注意到,代码的结构与我们之前看到的所有权层次结构匹配。该应用程序包含场景,而场景包含视图。或支持这些功能的平台上同一窗口中的新标签。Jeff将在稍后的演讲中详细解释WindowGroup的工作原理。我们的WindowGroup场景包含在由符合应用协议的自定义结构表示的应用中。您会注意到,代码的结构与我们之前看到的所有权层次结构匹配。该应用程序包含场景,而场景包含视图。

您可能还会注意到,我们的应用程序声明看起来类似于自定义视图声明。例如,视图和应用程序都能够声明数据依赖性。

在这里,我们的ReadingListViewer观察一个ReadingListStore对象。我们的应用程序还依赖于ReadingListStore对象,但是使用StateObject属性包装器将自己声明为该对象的所有者,这是SwiftUI今年的一项新功能。视图和应用程序都还声明了定义其用户界面内容的主体属性。前面我们讨论了视图如何由其他视图组成,这就是视图主体返回视图的原因。但是,应用是使用场景构建的,因此它的body属性会返回一个场景。最后,您可能会注意到@main属性装饰了我们的应用程序。这是Swift 5.3中的新属性,该属性允许类型充当程序执行的入口点。通常,Swift程序需要main.swift文件才能执行。使用@main属性,我们可以将这种责任委托给我们的摘要,而摘要将在启动时自动执行所有必要的设置,以使我们的应用程序显示在屏幕上。现在,我们已经审查了代码,让我们退后一步。我们在这里看到的是SwiftUI中基本应用程序的完整声明,仅适用于少数几行代码。但是不要让这个欺骗你。这个简单的声明中包含了大量的自动,智能行为。要真正了解此应用程序的工作原理,我们需要更多地讨论管理用户界面的WindowGroup场景。为此,我将把事情交给杰夫。我们在这里看到的是SwiftUI中基本应用程序的完整声明,仅适用于少数几行代码。但是不要让这个欺骗你。这个简单的声明中包含了大量的自动,智能行为。要真正了解此应用程序的工作原理,我们需要更多地讨论管理用户界面的WindowGroup场景。为此,我将把事情交给杰夫。我们在这里看到的是SwiftUI中基本应用程序的完整声明,仅适用于少数几行代码。但是不要让这个欺骗你。这个简单的声明中包含了大量的自动,智能行为。要真正了解此应用程序的工作原理,我们需要更多地讨论管理用户界面的WindowGroup场景。为此,我将把事情交给杰夫。


WindowGroup场景

谢谢马特。嗨,大家好。首先,我想通过简短的演示向您展示Matt在实践中概述的一些概念,然后再讨论WindowGroup的一些优点。我是一个非常狂热的读者,所以我一直在开发一个小应用程序,以跟踪我的进度以及我目前正在阅读的所有书籍。

如您所见,我的应用程序使用我指定为内容的视图在iPadOS上的初始窗口中启动。看来我在很多书中,所以让我们打开一些新窗口,以便检查进度。如果我打开应用程序Expose,则可以在这里轻松创建一个新书,然后导航到另一本书。WindowGroup在iPadOS上自动为我的应用程序提供此功能。您会注意到,我的每个窗口在界面中都反映了不同的状态。所选书籍在每一本书中都是不同的,并且对其进行更改不会影响其他书籍。这是SwiftUI中场景的关键方面。应用可以为要使用的每个场景提供共享模型,但是这些场景中视图的状态将是独立的。我还要指出应用切换器中的某些内容。我的每个窗口都显示我的应用程序名称以及所选书籍的名称。这是通过我们今年引入的新视图修饰符完成的-导航标题,在iOS上可用于在导航栏和应用切换器中填充标题。这是视图修改器的一个示例,它可能会影响其父场景的状态。在Mac上,通过在应用程序中使用WindowGroup来支持多个窗口是很常见的,SwiftUI将在文件菜单中提供一个菜单项,该菜单项支持创建新的可见实例。这会影响其父场景的状态。在Mac上,通过在应用程序中使用WindowGroup来支持多个窗口是很常见的,SwiftUI将在文件菜单中提供一个菜单项,该菜单项支持创建新的可见实例。这会影响其父场景的状态。在Mac上,通过在应用程序中使用WindowGroup来支持多个窗口是很常见的,SwiftUI将在文件菜单中提供一个菜单项,该菜单项支持创建新的可见实例。

也可以通过标准命令+ N键盘快捷键来调用此项目。

您会注意到导航标题如何在macOS上应用。书籍标题显示在Windows标题栏区域中。它还将在Windows菜单中使用。在这里提供良好的标题对于用户很重要。

由于除了为他们提供与其交互的内容的更多上下文之外,它还帮助他们从打开的窗口列表中选择所需的窗口。

除了支持多个Windows,macOS还支持将其窗口分组在一起。

通过窗口菜单,我可以将打开的窗口合并到单个选项卡式界面中。

每个选项卡由一个单独的场景表示。再次,我不需要为此功能编写任何代码SwiftUI自动提供此功能。

既然您已经了解了在应用程序中使用WindowGroup场景的一些实际含义,那么让我们进一步了解一些细节。回顾一下我刚才向您展示的内容,WindowGroup是一个场景,可让您表达应用程序的主要界面。您提供给它的视图将用作该接口的定义。这可以按预期方式在我们所有平台上运行。例如,在iOS和watchOS上,您的视图将显示在一个占据设备整个屏幕的窗口中。

在macOS上,将根据您的视图定义调整此窗口的大小。

场景的生命周期由运行它们的平台管理。

以macOS为例,当平台需要为您的应用程序创建一个窗口时,WindowGroup将实例化一个新的子场景,默认情况下,该子场景将在窗口中显示其内容。在支持多个Windows的平台(例如macOS和iPadOS)上,WindowGroup可以实例化多个子代。响应用户操作(例如单击菜单项或调用多任务手势),可能会发生这种情况。每个场景共享其用户界面的定义。构成此定义的视图均具有各自独立的状态。这意味着在一个窗口中更改视图状态不会影响另一个窗口的状态。使用此功能,您可以提供要用于界面的模板,同时让用户通过您提供的状态自定义此界面。

SceneStorage属性包装器可用于保留视图状态。

它采用唯一的密钥来标识要存储的状态。然后,该状态将由SwiftUI在适当的时间自动保存和恢复。现在,我已经向您展示了更多有关场景(尤其是WindowGroup)如何工作的信息。我想将事情交还给Matt,他将为您提供更多有关如何进一步自定义应用程序的信息。

谢谢杰夫。在结束之前,我想向您展示今年其他一些与应用程序相关的新功能。我们之前看到的读书俱乐部应用程序是一个由共享数据模型支持的数据驱动应用程序。但是还有其他种类的应用程序,例如基于文档的应用程序,就像我们在这里看到的ShapeEditApp一样。今年新增的是文档组的场景类型,它可以自动管理基于文档的场景的打开,编辑和保存。要了解更多信息,您应该查看今年的“在SwiftUI中构建基于文档的应用程序”讲座。现在回到我们的读书俱乐部示例,macOS应用程序的一个共同功能是首选项窗口。今年,我们将展示macOS上可用的新的Settings场景类型,它会自动设置标准首选项窗口。设置场景将自动在应用程序菜单中设置首选项命令,并为窗口提供正确的样式处理。说到菜单命令,SwiftUI还提供了一个API,供您使用新命令修饰符将自定义命令添加到场景中。BookCommands是我定义的自定义类型。

让我们快速看一下。使用与视图,场景和应用程序中相同的声明式状态驱动编程模型,命令API既强大又灵活。您可以将命令封装为自定义类型,并基于用户关注目标操作,类似于AppKit或UIKit中的响应者链,并可以使用常规视图自行构建命令。请查阅我们的参考文档,以获取有关使用命令的更多信息。这只是对SwiftUI今年推出的与新应用相关的API的一瞥。

我还建议您查看其他SwiftUI讲座,这将帮助您构建应用程序的内容。“ SwiftUI中的Data Essentials”将使您掌握如何在应用程序场景和视图之间正确传递数据的知识。在“ Swift的新增功能”中,我们将向您展示该语言的最新改进,可以改进您的所有SwiftUI代码。 我们非常期待看到您构建的所有出色的SwiftUI应用程序,希望您在论坛上与我们分享您的创作。我们喜欢您的所有反馈意见,迫不及待想看看您接下来要做什么。