看视频可以直观的获取知识,然而我们可能会遗失一些关键信息点。因此我汇总讲稿,方便大家可以反复快速学习。
开场白
技术交流
QQ:3365059189
SwiftUI技术交流QQ群:518696470
您好,欢迎来到WWDC。 Cody Brimhall:您好,欢迎来到SwiftUI中的Stacks,Grids和Outlines。我是Cody,是处理SwiftUI的工程师,在本演讲的稍后部分,我的同事Curt将加入我的行列。
SwiftUI 具有多种内置布局原语
SwiftUI具有多种内置布局原语,用于按水平和垂直顺序排列视图集合。这些原语可以单独用于满足基本的布局需求,也可以将它们组合在一起以构建具有自定义行为的复杂视图。
推荐开发模式
macOS中的新通知中心是通过SwiftUI实现的,它是工作中这种组合过程的一个很好的例子。简单的堆栈和网格使用层次结构,对齐方式和间距一起工作以组织大量信息,结果既美观又可用。在开发自己的应用程序时,我建议您以类似的方式考虑。
合成的重要性
SwiftUI的布局原语在设计时就考虑了合成。通常,当一个简单类型不能完成您需要做的所有事情时,前进的道路就是将它与另一个具有互补行为的简单类型结合起来。具有多种内置布局原语
演讲的主要内容
- 回顾最基本的类型,即水平和垂直堆栈,并介绍一对新的类型,以创建延迟增长的网格布局。
- 看一下现有Lists类型的新功能,该功能允许呈现分层数据
- Curt将深入研究轮廓和表单,并展示一些逐步显示用户界面控件的技术。
Stacks堆栈SwiftUI中最简单的布局原语
我将从堆栈开始,这是SwiftUI中最简单的布局原语。但是首先,为了谈论堆叠,我需要谈论三明治。如果您听了《 SwiftUI简介》演讲,您会知道我的朋友Jacob一直在努力制作三明治应用。我想自己是个三明治鉴赏家,我认为将Jacob的应用程序放到画廊视图中展示特别难忘的午餐照片会很有趣。
我要使用的数据模型非常简单:
- ID
- 名称
- 星级
- 画廊的英雄形象
在画廊中显示单个三明治的视图也同样简单。它显示可调整大小的英雄图像,并添加一个包含有关三明治信息的覆盖图。覆盖每个英雄图像的横幅视图使用VStack排列三明治的标题和星级评定指示器。星级只是图像的水平叠放。我最初的实现非常简单。我在展示我的画廊时使用的是一叠垂直的三明治视图。
使用Lazy的原因
随着拍摄更多照片,我的三明治列表将动态增长,因此我需要包含一个ForEach视图,该视图将枚举每个三明治并为每个三明治做一个视图。此外,堆栈不会自行滚动。因此,我需要将所有内容包装在滚动视图中。到目前为止,我对此非常满意。但是,当我开始在三明治照片的后部目录中加载时,我开始注意到一个问题。我的画廊需要显示的照片越多,显示时屏幕变得响应时间就越长。我想要的是一个惰性堆栈,该堆栈可以逐步构建自身,这样一开始,只有第一个充满图像的屏幕才需要渲染。其余的可以在用户滚动浏览图库时按需加载。
我们将引入两种新的SwiftUI堆栈类型,它们可以直接解决此问题。 LazyVStack和LazyHStack。延迟堆栈就像它们的VStack和HStack对应对象一样,只不过它们在可见时会逐渐递增其内容。这非常适合我的需求。该视图不会阻止主线程加载和测量每个图像,并且该应用程序的内存占用不会不必要地增大。我需要做的就是用LazyVStack替换我的VStack,现在我的图库会逐渐加载。我想在这里提出另外一点。如果您从评级视图的定义中回想起,定义英雄视图库的垂直堆栈并不是此处显示的唯一堆栈。每个HeroView都有自己的水平堆栈来布置星级评定指示器,还有一个ZStack可以将等级覆盖在英雄图像的顶部。
注意不是所以视图都需要lazy
因此,值得一提的是,由于我使外部堆栈变得很懒,所以这些堆栈也应该也很懒吗?在这种情况下,答案是否定的。虽然我希望垂直堆栈特别懒惰,因为它可以滚动,但是我不想花时间在大多数内容不滚动而无法看到的情况下预先渲染所有内容。另一方面,使给定英雄视图中的堆栈变得懒惰实际上并没有带来任何好处。该视图一出现在屏幕上,内容就立即可见,因此无论容器的默认行为如何,都必须立即加载所有内容。
通常,如果不确定使用哪种堆栈,请使用VStack或HStack。
Grids
使用LazyVGrid,我可以轻松实现多列布局以增加视图的三明治密度。让我们看一下它是如何工作的。这是我们之前看到的,为iPad扩展的同一个惰性堆栈。我将其更新为三列三明治,而不是一列。
与前面的示例的主要区别是我的布局容器。我使用LazyVGrid而不是LazyVStack,并且传递了一组值,这些值告诉SwiftUI如何计算网格中列的宽度。一秒钟内会更多。除了列描述之外,我还像定义堆栈一样定义了网格,方法是传入视图构建器以生成构成网格的各个视图。为了描述网格的列,我创建了一个GridItem值数组。每一项都指定如何计算单个列的宽度。在这里,我定义了三列。 GridItems默认情况下是灵活的,因此这种安排将用等宽的列填充网格。这与横向相同。列数是相同的,只是更宽。网格布局还可以适应可用于创建可变列数的空间。例如,在这里,我声明了一个自适应网格项,该网格项在保持指定的最小列宽的同时,会产生尽可能多的等宽列。这对于横向模式非常有用,在横向模式中有足够的空间容纳更多列。自适应网格项在macOS上也非常有用,在macOS中,可以任意调整窗口的大小。这些新原语的表现力令我感到非常兴奋。我想在移交给Curt之前讨论的最后一个主题是列表。列表不仅仅是基本的布局基元。它们是交互式的,并支持选择管理和滚动。列表内容总是延迟加载。现在我不认识你,但是到那时我已经吃了很多三明治。
开源个新App给大家ShapeEdit
让我们看一下Curt一直在开发的一个很酷的新应用,名为Shape Edit。 Shape Edit是基于文档的应用程序,可在macOS,iPadOS和iOS上运行。如果放大,我们可以在Shape Edit中看到Windows边栏视图,其中我们使用了一个列表来枚举画布中的形状。我们当前在画布上有一组图形,并使用图形数组填充侧栏中的内容行,从而生成平面形状列表。超酷。
我在使用此应用程序的过程中一直玩得很开心,以至于我被启发添加一个功能来将形状收集到组中。组还可以包含其他组,因此我们的平面列表现在需要表示任意深的元素树。
List中添加了一个新功能
我们在List中添加了一个新功能,非常适合此功能,我很高兴谈论它。要将列表变成轮廓,我只需要告诉列表如何遍历数据树即可。
我将使用新的初始化程序在图形模型上提供子级键路径,而SwiftUI将完成其余的工作。经过这一更改,我的侧边栏现在显示了完整的形状层次结构。太棒了正如您可能想象的那样,为了自动创建此轮廓,正在进行很多有趣的工作。
现在,我将交给Curt,后者将向您展示如何使用相同的工具列表在您自己的UI中实施渐进式披露。 ? Curt Clifton:谢谢,Cody。
将列表转换成这样的轮廓非常酷。我想深入了解它的工作原理。我认为细节非常棒,您也可以在自己的应用中使用其中的一些内容。 Cody向我们展示了Shape Edit如何绕过列表的子级键路径在边栏中显示图形的轮廓。
我一直认为在我们的应用程序中支持多个画布会很酷,并绘制了一个模型。该模型对每个画布使用不同的部分,并且在每个部分内部有单独的轮廓。让我们看看如何实现这样的自定义大纲。
正如Cody所提到的,列表是有助于管理选择的高级结构,因此我们保留了这一点。然后在列表中,我们使用ForEach遍历画布。对于每个画布,我们使用Section添加一个显示画布名称的标题。最后,本节的内容是SwiftUI的新视图:OutlineGroup。 OutlineGroup与ForEach相似,只是OutlineGroup遍历树结构数据而不是遍历平面集合。
这里需要一系列图形和子级键路径。 OutlineGroup生成一个轮廓,其中每个项目都是一个图形行。
让我们切换到Xcode,看看它是如何工作的。这是预览中显示的图形轮廓。 SwiftUI大纲不仅可以在macOS上使用,而且还可以在iOS上使用。在iPad和iPhone上具有强大的内置轮廓功能真是太好了。
让我们进行实时预览,看看这些组如何工作。我可以点击披露指标来展开和折叠组。让我们更新此视图以显示所有画布。首先,我们将在包装此图形行的列表内添加一个OutlineGroup。
然后,将前两个参数从List移到OutlineGroup。
请注意我们的预览如何尚未更改。直接在列表内部的OutlineGroup与使用children参数的列表相同。接下来,让我们将视图更改为使用画布而不是图形。通过单击命令并选择重复,将这个OutlineGroup包装在ForEach中。然后,将参数替换为模型中的画布...
...并重命名此参数。最后,我将更改OutlineGroup以在单个画布上遍历图形。现在,我们可以从所有画布上看到图形,但是它们都可以一起运行。让我们添加一些节标题。我可以按Shift-Command-L打开库,然后过滤以显示部分。我可以将其拖入其中,然后使标题显示画布名称。
注意,因为我们使用的是侧边栏列表样式,所以我们在iOS 14中引入了这些漂亮的粗体标题。我们也可以扩展和折叠它们。我觉得这很酷。通过分层列表和大纲组,SwiftUI在Mac和iOS上提供了两个很棒的新工具来逐步显示信息。有时,应用程序要求隐藏和显示不遵循常规层次结构的控件或其他信息,例如Inspector Popover。对于这种情况,
第三个新工具DisclosureGroups
我很高兴介绍第三个新工具DisclosureGroups。 DisclosureGroup提供了公开指示器,标签和内容。当您的用户点击或单击公开指示器时,将显示内容。当他们再次点击或单击它时,内容将被隐藏。让我们看看如何使用它。这是我们的检查员。我们具有用于调整填充,阴影和文本属性的控件。
所有这些都包装在一个Form中,这是此类控件集合的理想选择。您也可以在macOS的新“设置”场景中使用“表单”。让我们快速看一下检查器在应用程序中的工作方式。
Shape Edit在iPad上效果很好。我可以选择一个形状,然后打开检查器。我可以更改颜色,添加阴影甚至更改形状。让我们回到代码。这个检查器工作很好,但是有点忙。让我们看看是否可以整理一下。首先,我将所有这些填充控件包装在DisclosureGroup中。我将从库中获取一个DisclosureGroup ...
并设置标题以填充。注意,填充控件现在在检查器中一起折叠。就像轮廓一样,我们可以展开和折叠DisclosureGroup。该小组实际上可以使用一个图标。我们可以为此使用标签。我们只是删除了此便捷属性,并为标签添加了尾随闭包。
我可以在这里放置任何视图,但是新标签类型是在语义上组合标题和图标的便捷方法。我可以在这里使用出色的SFSymbol图像之一。我的最爱之一是rectangle.3.offgrid.fill。很好看让我们对阴影和文本控件进行相同的处理。完成此操作后,该检查员看起来非常不错。我只想更改一件事。
我认为我的用户会大量调整填充设置,因此我希望他们在打开检查器时可见。现在开始吧。 SwiftUI中的DisclosureGroups可以绑定到控制扩展的布尔属性。我将添加布尔状态以充当真相的来源...
...并将其默认设置为true。然后,我将配置DisclosureGroup以绑定到我们的新状态。现在,我们的填充控件默认扩展为-不错!我们已经了解了如何使用大纲和披露组来管理应用程序中信息的逐步披露。在总结之前,让我们看一下OutlineGroup的实际工作方式。这是科迪提到的构图原理的一个很好的例子。不必使用大纲和公开组来了解这一点,但我认为这很酷,希望您也能这样做。
探索原理
在这里,我们在一组图形上有一个OutlineGroup。 SwiftUI在相同的图形集合上将OutlineGroup扩展为ForEach。该ForEach的主体是DisclosureGroup。请注意,每个DisclosureGroup的标签都是使用原始集合的单个元素生成的,而每个DisclosureGroup的内容都是另一个OutlineGroup,这次是在该单个元素的子元素上。展开过程一直持续到找到没有子代的图形为止。但是由于SwiftUI仅在有人打开DisclosureGroup后才评估它的内容,因此实际上仅执行了最小量的过程。
如前所述,您无需了解使用大纲和公开组的轻松过程,但我只喜欢递归和组合的组合,这使OutlineGroup成为可能。实际上,我希望这次SwiftUI显示数据的工具会有所帮助。我们看到HStack和VStack是控制固定项目集放置的正确工具。新的惰性堆栈在滚动视图中非常有用,可显示可变的,可能较大的项目集。惰性网格提供了一种方便的新方法来在网格中显示集合。列表是强大的工具,可为您提供选择,滚动,内容的延迟加载以及今年新的分层数据显示的支持。使用窗体进行设置和其他控件列表,就像我们在检查器示例中看到的那样。最后,新的大纲和公开组使您能够定制适合您应用程序的渐进式信息显示。
下载源码
要了解有关如何最好地在应用程序中显示数据的更多信息,可以从developer.apple.com下载Shape Edit的代码。另外,请确保签出SwiftUI中的App Essentials,以了解有关在应用程序中创建设置场景的更多信息,以及签入SwiftUI中的Data Essentials,以获取有关将模型连接至视图的详细信息。有关三明治的更多信息,请查看WWDC20中的SwiftUI简介。