大多数浏览器和
Developer App 均支持流媒体播放。
-
集合视图布局改进
通过集合视图布局,可以轻松地构建丰富的交互式集合。了解如何制作从基本列表到高级多维浏览体验等不同复杂程度的动态响应式布局。
资源
相关视频
WWDC20
WWDC19
-
下载
欢迎大家 我的名字叫 Steve Breen 我是 UIKit 团队的工程师 今天和我一起的 还有我的同事们 来自 AppKit 团队的 Troy Stephens 还有来自 App Store 团队的 Abolfathi
今天我们将谈一谈 关于 CollectionView 布局的一些 改进与发展 下面我们的发言 将分成四大部分 首先 我们将回顾目前 这项技术的发展状况 也就是现在我们是怎么做的 我们如何定义 App 中的 CollectionView 布局 之后 我们会介绍一种 全新的方法 今年会将它应用到所有平台上 包括 iOS 和 tvOS 以及 Mac 接着 我们将进行一些 实际操作的演示 这样就能看到运行中的 API 了 最后 我们将为大家展示 更多的高级功能 以使这个 API 发挥最大功效
我们的内容很多 我们开始吧 首先我们说一说 现在这项技术的发展状况 我们现在是怎么做的呢 我们是如何定义 CollectionView 布局的呢
当 CollectionView 被引入 iOS 6 的时候 就有一个很新颖的概念 它用一个单独的抽象概念 来定义布局 因此它其实是 相互配合作用的两个类 一个负责渲染 另一个负责布局 也就是 CollectionView 布局 CollectionView 布局是一个 抽象的概念 所以我们必须将其编入子类 去使用它 我们之前在 iOS 6 中装载了 一个具体的布局类 称作 CollectionView 流式布局
流式布局对许多不同的设计 都十分有用 特别是在 iOS 6 时期 当时的情况 可能更简单一些 当时这么做是因为它使用的 是一种基于行的布局系统 去年 我们在 UI CollectionView 中讲到了它 但总的来说 一个基于行的系统 使你能够在正交轴上进行布局 设置布局轴 直到你填满 可用的空间数量 然后开始下一行 这种方法真的很不错 它运行简单 推理容易 你很快就可以做好布局 但是今天的 App 呢 随着设备的异构性增强 和屏幕大小的改变 在如今的 App 里 情况变得更加复杂了 在这里我们看到的是 装载在 iOS 13 中的 App Store 如果今设计师天交给你这样的设计 你会怎么办呢 你肯定会想 “好吧 我得选择如何进行设计” 因为现在我们可选的选项 远多于从前
然后你也许会选定 CollectionView 而如果你选定了它 你就会想 “我真的能在这里实现流式布局吗” 然后你有可能立刻放弃它
你所面对的 则是一个自定布局 并且 我看到你们在 Twitter 上 关于自定布局的讨论 它们可能会很复杂 去年我们在 CollectionView 的介绍中讨论过它 我们当时讨论了 创建一个自定布局所需要的东西
你需要 在你的具体的布局类中 提供一定数量的东西 我们也讨论了这些东西 同时我们也考虑到了 一些性能注意事项 这是你在设计一个自定布局时 所必须要考虑的事情 以确保当你的 CollectionView 中 有大量的项目时 它依然能快速运行 但我们并没有涵盖所有的情况 如果我们创建这些 自定布局的话 还会遇到其他的挑战
有很多这样的例子 我将在这里介绍一些 比如 补充视图 和装饰视图 都是可以在 CollectionView 里 搞得定的视图 而它们在自定布局里就有点棘手了 你只能靠自己了 同时还有自定尺寸这一挑战 你都得想办法解决 之后我们还会谈到这个 今年我们将一种 全新的具体的布局类 应用到平台中 作为流式布局的同级 我们称之为组合布局
好的 我们还没看过这种布局呢 什么是组合布局呢 它是做什么的呢
先讲一点原理 这是建立在什么基础上的呢 它有三个基本支柱 我们在上面搭建组合布局 首先 它是可组合的 也就是用简单的东西 来制作复杂的东西 同时它也是灵活的 你可以用组合布局 来写任何布局 它十分灵活 在默认情况下它的速度也很快 我们之前已经 在框架中进行了 所有的性能优化 因此在这里不用考虑这点 组合布局就是 描述或定义你想做什么 它是一种描述性的 API
“组成”这个词 你将会在本讲座中听到很多次 我们该如何用组合布局 来进行组成呢 我们会用小块的布局 这些小组件 将它们缝合在一起 这样你就用小块的布局 组成了更大的布局 我们已经从大量相关课程里 学习了流式布局 通过这些基于行的课程 你可以学习沿着行进行布局 我们也许知道有多少项目 也许不知道 但我们可以在这些小布局组中的 一行上布局项目
最后 正如名字所示 你不用设置子类 你只需要构建一个东西 然后将一些元素组合起来 之后就可以运行了 说了这么多还没有看代码 在这样的会议上 讨论的应该全是代码 我们来看些代码吧 这是一个 Hello World 组合布局 共有五行代码 现在 我要切换到 我这里的设备
这里展示的是我们的示例 App 接着是列表示例 哇 这个布局挺无聊的 看起来像个表格 这不重要 下面我们把重点 放在代码上 我们来看这个 这里我们马上 就会有一些发现 那第一个发现 因为我知道开发者们会说 “嘿 Steve 我可以在流式布局中 用两行代码完成这个 你这个有什么意义呢” 这种想法的确没错 你也许可以那样做 但在听完今天的整个发言后 我希望你们 记住和思考的是 当这些布局变得更多更复杂的时候 我们不会让代码量 随着问题的大小 呈线性增长 而是逐渐减少 因为我们只要将 新的东西组到布局中去 用一种非常简单的 容易推出的方法 来得到十分复杂的布局 我非常激动能向你们展示这些成果 第二个发现是 我想要你们看看 这些类型中有一个自然过渡 这里我们一共有五种类型 这里什么情况
我首先要关注的类型 是这四种类型 它们在逐级递进时 自然会看到这个抽象过程 我们从一个项目开始 这个项目被折叠成一个组 这个组又变成一个段 而这个段又变为我们的布局
现在 我们直观地看一下
这里 这个大矩形就是布局 这个布局是你整个的布局 然后这些明显的白色部分 代表我们的段 这会直接映射到 数据源 也就是 那些段中的内容 接着在这个具体的例子里 我们展示的是一种 传统的网格型布局 我们可以看到这些组 代表了我们的行 在里面的就是项目 这里主要是为了 展示这个将贯穿 整个演讲的层次结构 也就是这种重复的模式 项目 组 段 布局的模式
现在我想要 简要谈一谈 一些概念 在组合布局中的这些核心类型 只要我们弄懂这些 我们就可以直接跳到 实际演示中来检测其适用性 我想从设定尺寸 开始讲起 组合布局扩展了 设定尺寸的功能 让你更容易推出 在一个组合布局里面 如何设定尺寸 所有东西都有一个清楚的尺寸 每个东西的大小 都十分明确
现在 我们在这个欧几里得 二维几何平面上 用弯曲视图 因此 一个尺寸实际上 只是两个属性 一个是宽度 一个是高度 这里我们可以看到 我们得到了该类型的 简化版定义 它有一个宽度和一个高度 但要注意的是 宽度和高度这两个维度 它们并不是标量值 它不只是一个浮点数或其他 它其实是另一种类型 也就是 NSCollectionLayoutDimension
其实很简单 这是用一种不依赖于轴的方式 来描述一个具体的轴的大小 我们有四个不同的方法 来定义这个东西 我们用一种可视的方式 来完成这些
你现在有一个项目 你想要描述它 相对于其容器的大小 最外层的容器 将会是你的 CollectionView 在这里我们只说 这个项目的宽度 会是其容器宽度的 一部分或 50%
同样的 我们可以说 某个东西的高度 是其容器高度的一部分 在这里是 30%
因为我们可以用这种 不依赖轴的方法来描述某物 我们就可以用 具体的长宽比来定义某物 在这个例子里长宽比是 1 通过将宽度和高度 定义为一个维度 即其容器宽度的一部分 因此当它的宽度为 其容器的 25% 时 其高度也是 25%
这些就是 创建维度的分数变量 基于点的值呢 我们有两个 第一个是最简单的 绝对值 你把这个值设为 200 点 因为你的设计师 强调它必须是 200 点 那它就是这样的 接着在这里 就一个有趣的概念 估算值
如果你不知道具体的 项目的尺寸是多少 我们会经常这样说 你可以估计其大小 假设它是 200 点 随着时间的过去 它会随着项目的渲染而增长 我们对这个项目中的内容 也会更加了解
这就是布局的维度和尺寸
接下来我们来谈一谈项目 这很简单 这是一个储存格或者补充物 它是一个呈现在屏幕上的东西
你会在 STK 中看到更多的东西 但这只是那种类型定义的一小部分 我们发现当我们构建这些东西时 我们总要给它一个尺寸 所有的东西都要有一个尺寸 我们就接着说 按照抽象层级 已经说过了项目 下面我们来说组 所以什么是组呢 组是层级中的骨干 它就是你要 组成的布局的基本单元 有三种形式 水平 垂直 和自定 你可以把这些想象成 小型的流式布局 它们布局在水平轴 和垂直轴的一条线上 但要记住 我们之前说过 它是十分灵活的 如果你有一些东西 没有沿着该线进行布局 很多布局就都没有做到这一点 我们可以用一个自定组 那是什么呢
自定组让你以一种 自定义的方式 描述项目的绝对大小和位置 所以如果你有 预定义的生成器 来生成布局 那你就可以用自定组 或者如果你要做一个径向的布局 并且你想要计算它 那你也可以用自定组来完成 很厉害的是 你可以直接在垂直 和水平方向上组成自定义组 也就是用简单 构建复杂
这就是组 层级中的骨干
接下来我们要说 NSCollectionLayoutSection 正如它的名字所示 这是一种基于 CollectionView 中每个段的 布局定义 可以把该段中有多少项目 直接映射到该段的数据源 正如预期 我们看到 对段进行初始化 只需输入布局组 00:11:42.676 --> 00:11:45.106 A:middle 我们已经讲过了项目 组 和段
在这部分的最后 我们将讲到两个 顶级的布局类 在 iOS 和 tvOS 中我们有 UICollectionViewCompositionalLayout 而在 Mac 中我们有 NSViewCompositionalLayout
有趣的是 这些布局的定义都是一样的 无论应用在哪个平台 它们只是在顶级类上 有一些细微的差别 最后在这里要说的是 一件十分有趣的事 我们也会在之后的 演示中看到更多 构建一个组合布局的方法 有两种方法 最简单的方法是 直接描述一个布局段的定义 这和我们今天在流式布局中 所用的方法差不多 因为流式布局将每个段的量 定义为与其他所有段一样 因而它是均匀的
而组合布局则扩展了这个想法 因为现在我们有了 这种对段的定义 我们就可以指定一个闭包 该闭包将被调回 并将在每个段的基础上 请求这些段的定义 这样就带来了许多的可能性 因为现在你的布局 能够在段间 被完全区分开 在之后的演示中 我们会向你们展示很多 现在就到演示的部分了 关于类型的讨论已经够多了 下面我们要看看它的实际应用 这一部分就交给 我的同事 Troy Stephens Troy
谢谢 Steve
接下来 我们就来看一些代码 我们将深入探讨 一些实用的方法 我们如何用 Steve 刚才描述的 这些简单的元素 来构建任意类型的 你想要的布局 因此如果你还没有下载 本次讲座的示例项目的话 请务必下载 这样你就可以跟着做 还能有空的时候研究一下 最重要的是可以在你自己的项目中 免费使用我们的代码 而无论你想要完成 哪种布局的构建 你都能在我们今天 所讲的例子里 找到与之类似的案例 用我们的代码作为基础 进行你的布局 你将会更快更有效地 接近你的目标 我们将看到这很容易 我们利用任意现有的 组合布局描述 并逐步改进它 使之成为你想要的布局
当我们看完今天的示例 我想让你们注意的是 每一个例子中都有 相同的基本模式 这就是 Steve 向我们介绍的模式 每一个组合布局描述 都由四个相同的 基础部分组成 分别是项目 组和段的描述 以及包含三者的 整个布局 在接下来我们看的 每一个代码示例里 我们都将会看到相同的 四层嵌套结构 在更高级的讨论中 我们将看到如何 将组嵌套进其他的组中 利用这些简单的 易懂的部分 来构建或组成 更为复杂精细的布局 接下来我们来看代码
这里我们会从 我们的列表示例开始 这是 Steve 之前展示过的那个 在这里 这是我们 能想到的最简单的有用的布局 这一个单列列表 其中项目的宽度与 CollectionView 相当 如果我把手机转过来 我们能看到这些项目的确会 进行扩展以填充可用的宽度 但同时可以 保持原有高度不变 我们如何用组合布局 来实施这个呢 我打开了列表视图 控制器源文件 这就是我们 实施布局的地方 在今天要讲的每个例子里 我们进行了一个 CreatLayout 的函数 它能够灵活地将 组合布局的描述 打包封装起来 然后再返回来连接到 我们的 CollectionView 中 就像其他任何的 CollectionView 布局一样 这里要注意的第一件事 就是我们之前说过的 要从描述一个项目及其尺寸开始 我们先描述一个项目 然后用它来描述 一个项目组 接着我们把该组放进一个段里 最后我们创建并回到 我们的组合布局 这就是项目 组 段及布局的结构 这里值得注意的第二件事 也是我们在进入到 另一个例子之前 应该真正理解的事 是我们定义项目尺寸的方式 在这个例子中 组的大小最终决定了 项目的大小 下面我来解释一下原理 在这个简单的列表示例中 组似乎有一点多余 在一个组合布局里 一个组代表了一些 典型的重复结构 即一列项目 或一行项目 在这个例子里是一行项目 但的确在一些十分简单的例子里 每一行只有一个项目 这时每个项目都会有自己的组 但是组通常都是 组合布局描述中 固定的一部分 同时我们要用组 来帮助我们定义 项目的大小 之前 Steve 已经介绍了如何 用容器定义大小
我们先来看组的大小的描述 这里我们要求组 也就是这个例子里的行 扩展成容器宽度的 100% 这个组的容器就是它的段 而段会反过来扩大 布局或 CollectionView
同时 我们要求每一个组的高度 都是一个绝对值 即 44 点高
要注意的是 这基本上已经定义了 这个项目方框 就是我们想要的项目大小 即与 CollectionView 等宽 44 点高 在指定项目的大小时 我们需要做的就是 假设我们想要每个项目的 宽度都是其容器的 100% 高度也是 100% 这时该项目的容器就是组 这就是完成一个列表 所需要的全部信息 但有趣的是 在此过程中 我们会发现 我们并不需要在编码上 做大的改变 就能得到十分不同的布局 我们来看另一个例子 这里我要 打开我们的网格 这是一个无边框的 五列的网格
我们可以看看 如果把手机转过来 这个布局就变成了这样 这时我们的确仍然有五列 项目也仍然是正方形的 而项目大小随之改变 以适应这五列的宽度
在这个例子中 组其实要更方便一些 同时我们更容易理解
打开合格网格视图 控制源文件 看看这里创建布局的函数 同样的 还是这个结构 项目 组 段和布局 这看起来和列表布局描述 基本上差不多 这里唯一不同的就是 我们所设定的项目和组的大小 我们来看看能有什么不同 因为一组代表一行 我们仍然让每一组都 扩展到整个 CollectionView 的宽度 这很但这次我们不想让项目 与组的宽度保持一致 我们想要一行有五个项目 那在这个例子里 我们所要做的就是 在这里指定该项目的宽度 为其容器的 20% 该项目的容器是组或行 这时我们就 能够通过我们对 宽度的设定 使一行有五个项目 现在 我们来看高度 我们不设定一个绝对点值 我们说过想让每组 或每行的高度 是其容器宽度的 20% 注意 这里我们用这个方法 来指定横轴的 百分比宽度或高度 这真的很容易 这样我们就能让项目呈正方形 项目的宽度和组的高度 是一样的
同时因为组的高度 决定了项目的高度 在这里我们需要做的就是
这样创建一个网格 是很简单的 而我们现在所用的代码 与制作列表时所用的 并没有根本上的不同 如果设计师给你一个布局 通常来说 你会想要 在项目之间有一些空间 那接下来就看看怎样加这些空间 打开嵌入式项目网格示例 这仍然是一个 五列的网格 只是在项目之间 增加了一些空间
接下来打开嵌入式项目视图 InsetItemsGridViewController 我们来看 这里 如果把这些代码与 之前的例子相比 你就会发现 只有一行代码有所变化 这个发现很有用 因为你完全可以 把这个布局想成 和之前的无边框布局 几乎完全一样的计算
每个项目都会分配到 与之前给的无边框方块 一样的方块中 但在这个例子里 我们决定不通过 设定项目的大小 使其占据所分配的整个正方形 而是在最后 通过每个边上的 五个点 来嵌入项目的内容 所以这时候 项目的内容 就很有用了 而这个最后的步骤 是从已计算过的布局中减去一部分 这真的很棒 我们看过了如何创建列表和网格 还通过定义项目的大小 创建了网格 这里还有一种很好的方法 可以用来创建 含有行和列的网格状布局
我在这里展示给你们 这样就能熟悉它了 这里我打开 两列的网格示例 从表面上看起来 这和五列的网格很像 只是这里的列更少 的确 如果我把它转过来 它就变成了这样 仍然保持两列不变 而每个项目都扩展到了适当宽度
但是这与之前的做法 还是有所不同的 所以我们有必要讲讲 这里 在 TwoColumnViewController 中 我们要看的是 createLayout 函数
我们注意到 有趣的是 这里又一次出现了 项目 组 段和布局结构 但我们首先要注意的 这也许不会 立刻表现出来 即我们在创建代表着 每一行的水平组时 用了一种不太一样的方法 我们用一种不同形式的 初始化程序 该程序有明确的计数参数 这里我们就明确地设定 每一组需要有两个项目 即每行两个项目 如此一来 组合布局就会 自动计算出 项目的宽度 以满足这一设定 我们在这里像往常一样 设定一个项目的宽度 我们假设它是容器的 100% 但是顶部的值 最终会被覆盖 当你要求每一组都有 一定数量的项目时 组合布局 该组合布局就会 将其视为一种覆盖 然后就会计算出 真正能够满足 我们要求的宽度 我们也用一种不同的方法 增加项目与项目 之间的空间 组合布局提供了 很多方法来完成这一步 这让 API 变得十分灵活
在这个例子里 我们不指定 itemInsets 而是在段上指定 contentInsets 这里 我想在左右两边 都加上一点空白 我们只有一个段 所以这基本上就是我们整个的布局 我们想要 10 个点的前导间隔 和 10 个点的尾随间隔
注意当我们在这行代码上时 组合布局的设计会促使你 用不确定布局方向的方式 来表达你的布局 所以不用明确指出左右 我们只用指定 前导和尾随 这样真的很棒 因为当你用一种从右到左的语言 运行 App 的时候 你会自动得到 正确的布局 这里我们也用到一个组的属性 叫做 interItemSpacing 我们请求一个组 在其项目之间增加一定量的空间 在这个例子中 我们将其设为 10 个点 其他的都与前面的例子 非常相似 我们只用那个方法 来明确指定每一组的项目数
这样就相当不错 但 Steve 之前提到了 另一种很棒的功能 我想深入讲讲
他提到每个段 都可以有不同的布局 目前为止我们只看了 一个段的布局 但要是我们想要有多个段呢 而且每个段还要有 不同的布局呢 下面打开不同的 段的示例
现在这个布局 有点像我们之前讲过的 示例的合成 在这个布局中有三个段
第一段是一个简单的 类似于之前的单列列表 第二段是一个正方形项目的 五列网格 第三段则是一个长方形项目的 三列网格 那我们该怎么做呢
首先打开 DistinctSectionsViewController 看 createLayout 函数
第一眼看上去 它好像和之前完全不同 但实际上只是 最外层的组件不同 相比我们先前例示的布局 它不是在结尾 而是在开头 原因是这样 当我们例示组合布局时 用的是一个初始化程序 该程序将提供段的闭包 视为其参数 这是 Steve 提到过的 提供段的闭包 是一个任意代码块 因此你们可以想象 你可以通过返回任何类型的 你想要的段的布局 来对这个被调用做出响应 传两个指明具体段的参数 即两个段指数参数 在这个例子里 将会是 0 1 或 2 一个布局环境 包含了各种 你可以查到的有用属性 那个我们待会再看
这个闭包里的 其他东西都只是 和之前一样的代码 我们指定一个项目的描述 然后将其嵌入一个组的描述 最后 我们指定 一个段的描述 这就是提供段的闭包 所返回的内容 组合布局会 在需要重新查询 一个对特定段的 新的描述时 自动调用这个闭包 这里的内容就与 之前的十分相似 有趣的是 使各种布局有所区分的 主要是每个布局中 列的数量不同 我们已经有 这个 SectionLayoutKind 类型 它在源文件的顶端 我们来看一下 当我们将它初始化 我们就进入到段指数中 该指数为 0 1 或 2 它要做的就是将其映射到 一个告诉我们 SectionLayoutKind 要么是一个列表 要么是网格 5 或网格 3 的枚举类型中 我们还添加了 columnCount 这个方便易得的属性 这里我们可以直接请求 该 SectionLayoutKind 值 即在该布局中应有多少列 回到我们的 createLayout 函数 我们能看到在我们请求 该 columnCount 的地方 有两处不同应用 在两列网格的示例里 当我们将水平的组 初始化时 我们明确指定了 想要的列的数量 因此我们就交给复合布局 来自动算出 所含的是哪种项目宽度 我们还用列的数量 来决定布局中的 组或行的高度 来区分布局 你可以选择你想用的方法 真的很不错 但如果我们想要 调整这个布局呢 如果我们将手机转过来 可能空间就没有被 充分利用了 或许我们可以放更多的项目 那我们就来看看自适应段布局
第一眼看上去 这和上一个例子一模一样 但旋转过来之后 我们发现第一段 调整显示为两列 第二段调整为十列 第三段调整为六列 这个代码应该怎么写呢 其实和前一个例子很像
下面打开 AdaptiveSectionsViewController 看 createLayout 函数 这和前一个例子很像 我们最先注意到的不同 就是我们改变了 SectionLayoutKind 的类型 这里仍然有 SectionLayoutKind 但 columnCount 不再只是 一个可获取的属性 而是有一个参数的函数 这里我们给它传一个 从 layoutEnvironment 里获得的宽度 该 layoutEnvironment 类型里 就包含了一些信息 比如你的布局所要处理的 总的容器宽度 在 iOS 上它还包含 特征集合信息 因此你可以用这些信息 来计算出 什么样的布局 适合现在的环境 这里我们只使用宽度 如果我们看看顶部 我们在这里用了 SectionLayoutKind 我们可以发现该 columnCount 函数 现在是一个函数 它接受我们传入的宽度参数 在这个例子里 这是 CollectionView 的宽度 我们基本上实现了 一个布局改变 我们决定如果在我们的设备上 需要处理大于 800 个点的宽度 我们会用 wideMode 在 wideMode 里我们只要 在每个段中返回大量的列 就可以完成 如果我们返回 creatLayout 函数 我们就会发现 当我们得到列的数量后 我们所用的方法 可能还是和以前差不多 所以我们不用改变太多代码 就可以得到一个自适应 旋转的布局 这样就很不错 但目前为止 我们只讨论了项目 我们甚至还没有深入探讨 我们可以用补充视图 和装饰视图做什么 我最喜欢组合布局的 一点是 它使事情变得 前所未有地简单 我们能够超出页眉和页脚 使用你自己设计的 任意的补充视图 接下来的部分 我们将进入 一些更高级的话题 一些你可以用组合布局 完成的很棒的事情 下面就继续交给我的同事 Steve 谢谢
既然我们已经 看过基本的工作原理 知道如何创建 和运行组合布局 接下来我就要带大家进入 更高级的话题了 因为我们有很多种方法 可以用组合布局 来创建自定布局 首先我要接着 谈一谈补充项目
CollectionView 可以做三个基本的 视图类类型 包括储存格 即用来表示 模型对象的交互对象 同时它也代表着 补充项目和装饰项目 它们是为了装饰 布局的其他部分 来给你一些关于内容信息的 视觉提示 比如 一个储存格上的标记会说 “嘿 你有一条推特评论” 或其他什么
今天我们会看到一些 这三个例子的常见用法 即标记 页眉和页脚 现在我们有流支持
它们在内容上方浮动 但我们可以在 组合布局里进行扩展 使其变得更容易 我们可以用这个概念简化它 将内容锚定在 你布局的一个项目或组上 这样可以简化视觉关系 这是怎么做到的呢 我们来直观地看一下 这里 我们能看到 有一个新的类型 NSCollectionLayoutAnchor 我们在这里设定 这两种类型的关系 我们的补充物就会 通过与一个主空间 一个项目或组的几何形状 相对应的方式被锚定 这非常容易推出
那这里我们马上看到 我们创建的 NSCollectionLayoutAnchor 我们指定边缘 我们想要把这个项目固定在 该储存格顶端的尾随边 我们想让它稍微 超出几何图形 我们可以用分数高度
这里我们能看到这个设备 我们已经放上了这些标记 得益于我精湛的设计技巧 这里有一个四个项目的网格 由浅蓝色的储存格组成 这里我们能看到 在一些项目上 有小的通知标记 它们是在说 “嘿 你需要注意这里”
而这里的这些标记 就稍稍超出了几何图形 它们不完全在 储存格的几何图形里面 我们回到幻灯片上 快速浏览一下 就是 fractionalOffset 使它们能稍稍超出几何图形 现在我们将 在正 X 上移动 30% 然后在负 Y 上也移动30% 然后我们用 badgeSize 和 elementKind 定义 CollectionLayoutSupplementaryItem 我们要用 已注册的补充类型 重新回到 CollectionView 的视图类 然后我们指定容器的锚 指定它如何进行关联 既然我们有了 这个补充物的定义 就要把它和一些东西关联起来 我们要把它与一个项目 一个储存格相关联 在这个例子中 我们要用一个带有 一系列补充物的初始化程序 的扩展变体 来进行初始化 就是这样 页眉和页脚呢 页眉和页脚 与这些项目的补充物 只有一点点不同 当你想到 用一个补充页眉和页脚 来装饰的内容时 你并不想让 补充页眉或页脚 遮挡住真正的内容 需要扩展内容的区域 以便看到内容本身
在这个例子里 我们有很多不同的补充物 叫做边界补充物 我们要把它放在 主几何图形的补充物 的边界上
我们可以为段或整个布局 制作这些边界补充物 我们可以将它们 固定在这整个平衡中 完成一些很棒的布局 下面我将切换到 设备上的例子
就是这样 我们看看这个例子 很简单易懂的例子 这里有一个固定在段上 的页眉和页脚 上下滑动 发现这就是我们想要的 下面来看代码
这个和几分钟前说到的 BoundarySupplementaryItems 代码很像 现在除了这个容器锚 这里还有 对齐属性 这里为页眉指定了顶部 为页脚指定了底部 因为想到达几何图形的 段的顶部和底部 为了确保页眉浮动 并固定在段中 它所在的内容区域 我们只需指定 PinToVisibleBounds 接着我们需要将页眉和页脚 与它们要进入的 几何图形关联起来 也就是段 这里我们就用 BoundarySupplementaryItems 阵列
很简单吧
目前为止我们展示时 都用的是全新的 iOS 13 卡片 这种卡片设计语言 贯穿整个系统 我们在滚动 UI 中也能看到 各种各样的内容 都用卡片 以逻辑方式组合在一起 这自然很适合 CollectionView 因为我们一直 支持装饰视图的概念 在过去你需要自己进行运算 但在组合布局里 这就变得很简单 我们用一个 CollectionLayoutDecorationItem 进行支持 你只要用一个 elementKind 来创建它就可以了 这么做是为了 在段的内容之后 产生一个视图 以提供良好的视觉分组 想要创建它 只需要一行代码 想要将它加到段里 你只要指定项目 这样就可以了 就是这样 那我们来快速浏览一下 这组代码的结果 非常简单也非常直观 这是包含多个段的列表 我们增加了装饰视图 只用了一行代码 很简单
下面是一个我 非常关心的话题 估算自定尺寸
在 iOS 13 中我们花了 很多时间来确保其速度快 准确性高
组合布局以非常具体的方式 扩展了估算自定尺寸 这一概念 它允许你按每个轴来确定尺寸 这非常重要 因为通常你想要 在你呈现内容时 得到良好的视图层次 你并不想要完全 被限制在轴线上 不想只能在 X 轴上 和 Y 轴上增长 比如你可能知道 这个东西的宽度 举一个页眉和页脚的例子 我们希望它的宽度 恰好是 CollectionView 的宽度 但是 我们希望它的高度 有一点变化 快速看一下这个例子 我们之前已经看过这个代码了 所以这里 我们看到非常熟悉的 段 页眉和页脚 然后我从这里下拉 打开文本大小部件 把它放大
这里所有的东西都变大了 这就对了 是吧 这是怎么做到的呢 这里我们能看到 heightDimension 是估算的 这就是唯一的不同 我们指定了 我们知道的确定宽度 但我们不知道具体高度 我们只是将其估算为 44 个点 随着内容的呈现 我们有了更好的想法 我们可以使布局自动作废 这些都是自动的 这使得你的 App 更容易支持动态类型 即使其中包含 补充物 页眉和页脚 所以 这是很不错的
现在我们来说一些 很有趣的东西 怎样嵌套呢 我们之前说过组成这个概念 我们来看看要怎么做 组合布局的 核心布局是布局组 布局组其实是 NSCollectionLayoutItem 的一个子类型 因为有了这样的关系 当你指定一个 布局组中的项目时 你还可以有其他的组 你可以将它们嵌套 这个嵌套是没有限制的 它是任意的 因为这一点 我们解锁了很多有趣的新设计
那在这个例子里 我们看到一个组里有三个项目 我们看到在前导侧 有个大方块 在尾随侧有个垂直的组 那这个怎么在代码里推出呢
这个很简单 底部有一个 水平的组 其子项分别是 leadingItem 和一个 trailingGroup 我们很容易 推出这样的东西 我们现在就看看要怎么做 只需添加一些额外的东西 就可以得到这些很棒的布局 嵌套组是很有用的 嵌套 CollectionView 呢 好的 这里我们看到的是 App Store 是 iOS 13 的更新 我不知道你怎么看 但如果我是一个 第三方开发者时 要是交给我这样的设计 我会心脏病发作的 这真的很复杂 很有挑战性 因为有很多簿记工作要做 但这是一种常见的模式 在今天的 App 中 我们也经常看到它 要使其外观好性能棒 这一点就颇具挑战性 组合布局能用 一行代码来解决这个问题 下面我就给你们展示一个示例
这里的组 和之前的一样 但我们注意到这个组 铺得更平了 它大概占了容器宽度的 80% 这是一个垂直滚动的 CollectionView 里面有五个段 但每个段都可以 用这一行代码垂直滚动 这里有很多不同的变化 请容许我 切换到这里 我们有五种不同的方法 对 这里还有 我不想看到的无的情况 有两个连续函数的例子 然后是三个分页函数的例子 我将用可视的方式 来讲每个例子
先向大家演示我们 垂直滚动段的行为 正如你所期待的那样 这是一个十分简单的 滚动视图的行为 这里有一个弹回 这个很棒 我这么滑几个小时都不会烦 好了 这只是正常滚动视图的行为 但在连续函数里 我们还有一个另外的 流体滚动视图行为 我们称为 continuousGroupLeadingBoundary 这有点拗口 但描述得很到位 当我们滚动然后松手时 我们自然会停留在 该组语义前导 的边界上 鼓掌的人以前一定做过 定向内容偏移或提议过偏移 所以你们知道有多痛苦 好了 说完这个连续行为 我们来说说分页行为 这个也很酷 这就像是普通的 滚动视图分页行为 我们称之为分页
很有创意 在这里 我们能看到 无论用户用怎样的速度进行滚动 得到的都只是一页的内容 这个页面被定义为 默认滚动视图行为 它的宽度是 CollectionView 的宽度
这里还可以有两种变化 你可能已经猜到了 接下来我们要说组分页的概念 现在我们有关于 一个组的语义概念 我们就就可以将组的大小 设置为页面的大小
这样真的很棒
这样你可以自动得到 没有遮挡的内容 你的内容总是 呈现在前面和中间 最后要说的是组分页居中 这个和组分页很像 但现在我们会自动把该组居中 对 看上去很棒 这样就是一种很好的 显示部分内容的效果 你可以看到前导 和尾随两端的内容 你就会很清楚你所在的位置
这就是一些 应用在组合 App 中的 高级的附加特性 诸如此类的还有很多 你可以打开 SDK 来查看
在 Apple 协作的概念 是非常重要的 我们要与全公司的团队 进行合作以解决问题
作为一名框架工程师 对我们来说 与公司中不同的团队合作 确保我们知道他们 对新框架特性的需求 是非常重要的
其中一个团队 App Store 团队就在 iOS 13 中做了重新设计 他们真的很想 简化一下代码库 所以在沟通的过程中 我们讨论了组合布局 他们对此非常兴奋 用它写了很多代码 下面我们就有请 来自 App Store 团队的同事 Dersu Abolfathi 为大家介绍 Dersu 谢谢 Steve
有数百万的用户 在 App Store 中 寻找合适的 App 以使其设备充分发挥效用
在座有很多人每天 都会访问 App Store 里面的内容就要丰富 吸引人而且有活力
CollectionView 在这其中 发挥着关键作用
这是 App Store 如果你今天想要只用 流式布局来构建这样的 UI 你可能会从 一个竖直方向滚动的 CollectionView 开始
而对于每一个 在水平轴上滚动的段 你都需要一个附加的 CollectionView 这意味着你需要有 更多的支持代码 来连接每个集合的演示和行为
而在组合布局中 只需要一个 CollectionView 就可以完成 事实上 我们已经这么做了
在 iOS 13 中我们用组合布局 重新设计了 App Store 你在此页上看到的 每种内容类型都能进行 它们自己的布局描述 所有的这些布局段 一起组成一个整体的 CollectionViewLayout
我们只用一个布局项目 就能描述这个段 该项目有一个已知的高度 而宽度则为容器的 100%
布局项目位于一个布局组里 而布局组本身 占据容器宽度的一半 这些都是 让 UI 运行的基本构件 我们拿出该布局组 将其贴在一个布局段中 然后为了得到想要的分页行为 我们将垂直滚动行为 设置为组分页 然后好戏就开场了
在 iOS 13 的 App Store 里 UI 也支持 从右向左阅读的语言 组合布局帮助实现了这一功能 我们用所有 今天能看到的 相同的原语来构建布局 组合布局只负责剩下的部分 它确保我们的补充物 和储存格的位置 适合从右到左的环境 此外 我们不再需要 单独写一行代码 来确保我们的分页行为 也适用于从右到左的布局方向
所以这个新的 API 使我们能够获取所有那些 我们之前从头管到脚的可滚动区域 并将它们平铺到 顶层的一个 CollectionView 中 这样一来我们的代码 变得更加简洁 更易于推出 同时也更易于日后维护
组合布局重新定义了 我们在自己的 App 中 思考 CollectionViews 的方式 我们迫不及待地想看看 它是如何提升 你们在 App Store 中 所得到的 App 的体验呢 下面交给你 Troy 非常感谢 Dersu 这个设计真不错 我们非常高兴地看到 我们已经用组合布局 简化了一个知名的 面向用户的 App 的开发过程 我很高兴在我们的平台上 开发人员能 使用同样的API 说到这儿 我想给你们 快速地展示一下 组合布局用 NSCollectionView 在 macOS 上的运行
当你打开你在 Xcode 上 下载的示例项目时 注意会有一个 Mac 的构建方案和目标 我们要在这里构建且运行它
我们打开 我们在本次讲座中看过的 所有布局示例 然后把它们分散开
就是这样 这就是我们的 各种组合布局的例子 而我们用的代码 本质上都是一样的 我们也将得到相同的 API 你真正看到的 唯一的调整就是 我们想要在其中应用 更多适合 macOS 的指标 这里可以水平滚动
当然 在 Mac 上我们想要 它们以 Mac 的方式运行 我们在 Mac 上 使用 CollectionViews 时 它们是可以不断调整大小的 我们已经确保 Mac 能又快又好地进行 超轻量的大小调整 布局也调整得非常快 我们的自适应段布局 和之前一样有一个布局改变 既然你知道了运行原理 你就可以随意地增加 额外的布局改变 给更大的窗口宽度和屏幕宽度 当然 我们还有一些特性 比如点击项目就能选中它们 用箭头键就可以进行导航 按住 Shift 键 同时按箭头键 就可以选中多个项目 当然 也可以拖动选择任意区域 可以大批量选择项目 这个在任何的 组合布局里都可以完成 包括像这样更高级的布局 所有用户期待 在 Mac 上实现的东西都可以做到 我们已经运行所有这些布局 下面这些代码已经说得够多了 项目 段和组的描述 在所使用的 API 中 是相同的 你甚至可以提取代码 并在不同的平台项目之间 分享这些代码
所以我们可以看到 这里的组合布局我们 在不同的平台上的操作 变得更加容易 它确实有很多值得推荐的地方 从今天开始你就可以 在 iOS tvOS 和 macOS 上使用它 我们只要简单地描述它 就可以轻易地为 CollectionView 创建新的自定布局 我们认为这是一个打破格局的创新 反过来 这使得 CollectionView 成为一个 比以前更全能的工具 你可以随心所欲地 展示你的内容 你可以更容易地 描述新的布局 调整和改变布局 尝试不同的东西 并进行迭代 这些都将使设计人员 能够更快地进行迭代 这的确是个改变游戏规则的创新
所以等你们回去 打开示例项目进行试验 尝试改变不同的事物 以我们的代码作为基础 为 App 的下个版本 创建自定布局吧 我们迫不及待地想看到 组合布局能够使你 在很短的时间内 创建出更好的用户体验
如果你本次讲座很感兴趣 我们还有一个话题 我想你也会非常喜欢 特别是使用 CollectionViews 甚至是 UI 表视图的朋友 在UI数据源方面的发展中 我们引入了一个全新的 非常简单的 API 用于向 CollectionViews 和 UI 表视图提供模型数据 同时免费获得 对差异的自动计算 和自动动画 它将创造令人愉快的 用户体验 所以一定要观看这个讲座
感谢各位的聆听 [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。