大多数浏览器和
Developer App 均支持流媒体播放。
-
为 iPad 打造
了解如何改进 iPad app 从而利用增加的屏幕尺寸和 iPadOS 附加功能,并帮助用户使用其设备完成更多工作。了解如何构建详细的多列布局并将列表集成到你的 app 中,且无需调整现有代码。 我们还将了解减少视图中的模态,减少轻击和触摸次数,从而更轻松地浏览界面。 要想充分利用本节内容,建议先大致了解 iPad app 布局和 UIKit。获取更多信息,请观看“让 app 具有适配性”。我们还建议你熟悉 UICollectionView,这能对你有所帮助。 获取内容概要,请观看“网格视图布局中的最新功能” 。 若想进一步了解为 app 创建列表,建议观看“ UICollectionView 中的列表”。
资源
相关视频
WWDC20
WWDC19
-
下载
(你好 WWDC 2020)
你好 欢迎来到 WWDC (为 IPAD 打造) 你好 我叫 Kurt 欢迎来到 WWDC 我今天要为大家讲的是“为 iPad 打造” 我们要讨论的是 如何使用 iOS 14 的新功能和新外观 让你的 app 在 iPad 上运行得更好 我们重新设计了我们的 apps 比如邮件、备忘录和家庭 以充分利用 iPad 的强大功能 我将指出一些你也可以实施的 特定 UI 特性 邮件有了新的面貌 拥有了多个栏目 你可以很容易地看到 你的电子邮件或你的所有邮箱 只需几个简约的手势 你就可以隐藏或显示你想要的内容 侧边栏列表设计简约而清晰 当我点击编辑按钮 现在有很多可用的控件 构建一个简约的列表 然后向其添加附件很容易 在备忘录中 我们已经让工作 变得更容易完成且不需要任何额外的点击 例如 我打开选色器 为我的记号笔选择一个颜色 当我在文档中绘制时 它无需点击即可自动关闭 选色器 这里还有一个例子 iPad 上家庭的新设计 有一个带有列表的侧边栏 当你使用 Catalyst 将你的 app 带到 Mac 上时 所有这些功能都能在 Mac 上运行 但它们也使用了新的 Mac 设计 我们会告诉你 如何使用 UIKit 中的新功能 对你的 app 做同样的事情 多列分屏浏览现已可用 我们会为大家提供一个概览 我们将讨论如何在这些列中实施列表 以及如何获得正确的外观 我们会讲到减少你的 UI 中的模态 并且我们会给出一个例子 来说明快捷键 app 是如何做到这些的 所以 让我们开始吧 多列 app 的核心是 UISplitViewController 它是一个容器视图的控制器 它为你在视图控制器中提供的内容 提供结构 在 iOS 14 中 有了新的 API 使它易于设置和使用 使用这个指定样式的新初始化器 使用这个初始化器 可以启用新的行为和更多新的 API 样式预先说明你想要多少列 对两列使用双列样式 我们称它们为首要和次要的 然后你通过调用 setViewController 来指定哪个视图控制器在哪个列中 例如 家庭可以为首要列提供一个视图控制器 为次要列提供另一个视图控制器 三列同样简单 使用三栏样式 在首要和次要之间的是什么呢? 我们称中间的这一列为“补充列” 同样 调用 setViewController 来为补充列 提供视图控制器 例如 以下是邮件中如何设置其补充列 这就是 获得双列和三列布局所需要做的全部工作 我们之前已经提到过了 但是为了强调 我们建议你为 iPad 和 iPhone 打造同一个 app 如果你的 app 是分列结构 使用 UISplitViewController 作为你的窗口的根视图控制器 它通过在正确的时间和正确的地点 显示正确的视图控制器来为你处理列 发生的情况基于尺寸类别 有些情况下会有很多水平空间 比如 iPad 全屏和大屏幕 iPhone 的横屏 我们称之为标准宽度尺寸类别 因为有太多的空间 UISplitViewController 可以并排显示多个列
在其他情况下 没有那么多的水平空间 比如 iPad apps 的侧拉和 iPhone 的竖屏 我们称之为紧凑宽度尺寸类别 显然没有空间显示多列 那么我们该怎么办? 你可以选择指定一个单独的视图控制器 当宽度被压缩时使用 它可以使用一个不同的浏览方案 为可用空间量身定制 你通过调用 setViewControllerForCompact 为该列提供另一个视图控制器 这样就行了 剩下的交给我们 例如 这里有一个快捷指令 他们使用标签栏控制器 来实施不同的浏览方法 可在较小的区域中奏效 总而言之 不要把它看作是 设计一个 iPad app 和一个 iPhone app 相反 你要设计两种体验 有多个列的标准宽度及没有列的紧凑宽度 让我们回到多列的讨论 我们有很多方法来布局这些列 这取决于我们有多少空间以及它们的大小 我们称之为显示模式 我们可以只显示次要列 当你专注于你的内容时 你已经隐藏了所有其他的列 你可以在你的次要列旁边显示一列 或者在次要列之上显示一列 如果有三列的话 则有更多的选择 你可以在次要列旁边有两列 或者在次要列上面有两列 甚至可以代替它 将其推到一边
为了在这些显示模式之间移动 SplitViewController 自动创建适当的按钮 并使它们出现在正确的位置 例如 这里我们通过按按钮来显示和隐藏 备忘录中的列 你也可以从侧边轻扫来显示更多的列 也可以通过点击来隐藏所有的列 按钮和手势由 presentsWithGesture 属性启用 默认情况下 它是“启用” 但如果设置为“禁用” 那些按钮和手势就会消失 showsSecondaryOnlyButton 属性启用一个附加按钮 该按钮隐藏除次要列之外的所有列 你们刚刚在备忘录上看到了 设置 preferredSplitBehavior 属性 来决定按钮和手势将使用什么显示模式 例如 如果你喜欢在你的 app 中列是并排的 使用平铺显示行为 按下按钮将在这些显示模式中转换 置换显示行为与此类似 但是当显示三列时 我们将次要列部分推离屏幕
覆盖显示行为 当然就是使用覆盖显示模式
在任何时候 你都可以请求隐藏或显示一列 只要说明你想改变哪一列 UISplitViewController 将自动进行平滑过渡 以满足你的请求 最后 如果你知道 你的 app 总是想要相同的布局 请使用首选的显示模式来指定 例如 像提醒事项这样的 app 总是希望有并排的两列 就会将首选的显示模式 设置为“次要列旁一列” 我说过按钮会自动添加 这是怎么做到的呢? 因为现在每一列都有一个浏览控制器 它会自动为你创建 每个浏览控制器在顶部有一个浏览栏 在底部有一个可选的工具条 这意味着 UIKit 可以在这些栏中放置按钮 你也可以使用标准方法 还有很多的细节 我们建议你查看说明文档 以进一步了解 关于新的委托方法、控制列宽度的方法 以及如何在转换的同时进行动画操作 Human Interface Guidelines 还解释了 如何使用分屏浏览 现在让我们了解一下每一栏的内容 通常 你希望在首要列和补充列中显示列表 例如 邮件在首要列视图中显示邮箱列表 在补充列视图中显示邮件消息列表 显示列表的现代方法 是使用 UICollectionView 它非常强大、非常灵活 这也是我们建议以后使用的 有一个概述视频解释了所有新的 API 名叫“UICollectionView 的改进” 我将关注一个特定的主题 为首要和补充列提供正确的外观 我将给出一个需要遵循的方法 让我们深入了解如何设置集合视图 这对于所有的列表都是类似的 但是我们将用一个 包含不同天气种类的例子来说明 每个项显示一个图像和一个标题 我们在创建集合视图时执行一次设置 要创建集合视图 我们需要一个布局 布局会具体说明项目 如何在垂直列表中排列的详细信息 我们根据列表配置创建一个布局 它指定单元格的默认外观 是否有页眉和页脚以及其他细节 当我们编写代码时 它是由内而外的 首先 我们做一个列表配置 这是一个使用侧栏外观的 UICollectionLayoutListConfiguration 你还可以改变其他的外观和属性 但先从默认值开始 然后用列表方法把布局做成 UICollectionViewCompositionalLayout 让它成为一个简约的垂直滚动的列表 并且它基于你已经创建的配置 最后 创建集合视图并为其提供布局 我们只操作一次 就不用再碰它了 接下来 我们将数据连接到列表中单元格的内容 这就是 app 的细节 在本例中 我有一个名为 MyItem 的简约结构 它包含一个标题和一个图像 我的数据存储是这些结构的数组 这里有一个实例 标题是“晴天” 图像是显示太阳的系统图像 现在 我们需要一些代码来把这个结构的实例 在单元格中加以显示 iOS 14 中有一个新的简约方法 你创建一个 CellRegistration 也就是说 给定特定类型的单元格和特定类型的数据 这是运行的代码来将数据放入单元格中 对于一个列表 你希望单元格类型是 UICollectionViewListCell 这个单元的样子有很多可能性 这是很笼统的 我们在设置内容的时候 会包含一个图像视图和旁边的标签 我现在显示的是问号因为我们还没有填写 数据类型由你决定 在这个例子中 它是 MyItem 现在让我们填写代码 我们使用这些类型 创建一个 cellRegistration 并给它一个运行的闭包 闭包指定了 单元格、集合视图上的索引路径和项目 接下来 我们使用新的 contentConfiguration API 来指定单元格内容 对于不同外观的单元格 有几种内置的内容配置 但通常你希望使用单元格的默认配置 我们只需要将项目的属性 转移到内容配置中 然后 最后一步 将该内容应用到单元格中 当你的代码被调用时 它将填充单元格 你将看到结果
最后 我们将连接最后一部分 创建一个 UICollectionViewDiffableDataSource 这告诉集合视图要显示哪些项 它基于你的数据存储 将项目从数据存储区推入其中 然后 数据源调用其闭包来创建要显示的单元格 这里有很多步骤 但是所有的列表都遵循相同的模式 创建数据源 为该部分提供一个类型 因为集合视图可以包含多个部分 每个部分都有 MyItem 类型的项 使用特定的 collectionView 初始化该数据源 当数据源需要一个单元格时 将使用索引路径和项调用此闭包 你需要返回一个单元格 使用前面创建的单元格注册 你调用 dequeueConfiguredReusableCell 它负责设置每个单元格 其他一切都将为你处理 包括重用单元格以获得良好性能的 所有细节 这段代码对于大多数列表都是相同的 有趣的部分是项目的类型和单元格注册
以下是它的结果 漂亮的列表和正确的外观 注意 我们会自动调整所选单元格的背景颜色 使其在每一列中不同 所有这些外观都是可定制的 我们前面创建的每个对象 都有可以更改的属性 例如 在显示内容列表而不是浏览时 你最好在补充列中使用稍微不同的外观 设置集合视图时使用 appearanceSidebarPlain 你会看到不同的外观 背景是白色的 还有分隔标记和其他细微的差别 Human Interface Guidelines 提到说 如果你有一个内容列表 比如集合或文件夹中的项 那么就使用侧边栏朴素外观 这在补充列中很常见 使用集合视图 你可以做更多的事情 下面是一些关于邮件和文件的例子 你可以添加一些配件 比如勾号 你可以通过拖动项目来重新给它们排序 可以使用大纲功能 来折叠和展开层次结构中的项 你还可以 向行添加轻扫操作 例如 删除文件夹 如果你还在使用 UITableView 我们强烈建议你换到 UICollectionView 这使得添加所有这些功能 并获得所有新的样式和外观变得很容易 最后 让我们简单谈谈减少模态 在 iOS 14 中 我们尝试在一些常见的场景中 去掉界面 这减少了你完成任务所需要点击的次数 在备忘录中 我们使界面更加流畅 我打开选色器为我的记号笔选择一个颜色 然后我在文档中绘制 它会自动关闭选色器 我不需要点击就能关闭弹窗 然后再触碰一次就能开始画画了 所有这些额外的点击加起来会很费时间 这里有另外一个例子 在联系人里 我按下一个按钮来显示一个菜单 传统上 这时我们会调暗视图 但是我们会要求你在菜单外点击来关闭它 现在 在 iOS 14 中 触摸菜单外就会关闭它 你可以继续用同一触碰来滚动 我们在 UIKit 中安装了它 所以你会自动获得 我们鼓励你在你的 app 中做类似的事情 每个 app 都是不同的 所以我们没有精确的配方 但我们确实建议 需要关注用户的动作 如即将发生的活动或滚动 并将它们作为信号 消除任何可能成为阻碍的瞬时 UI 现在你知道了如何使用多个列和列表 并且了解了如何简化模态 快捷指令 app 采用了所有这些 我们认为它是一个很好的例子 接下来 我将请 Natalia 来解释快捷指令是如何做到这一点的 我来谈谈快捷指令 app 是如何为 iPad 重新设计的 你今天在这里学到的东西将帮助你 为你的用户打造一个很棒的 iPad 体验 让我们开始吧 这是在 iPad 上的快捷指令 我们重新设计了它 以充分利用 iPad 的大屏幕 为了更方便浏览 我们用侧边栏替换了标签栏 这使我们能够提供更多的浏览选项 由于侧边栏是可折叠的 因此显示也可以定制 让我进一步说明我们是如何做到的 正如 Kurt 之前所说 分屏浏览控制器 是多列布局背后的驱动力 首先我来谈谈 我们如何使用新的分屏浏览控制器 API 重新设计快捷指令 然后我再讲一下侧边栏 你会看到它的所有组成部分 在这个讲座结束时 你会对这些 新的 UIKit API 如何结合在一起创建一个 很棒的 iPad 体验有一个很好的了解 首先 让我们看看分屏浏览控制器 分屏浏览控制器是快捷指令的支柱 是 API 让我们 有这两个不同的视图控制器 并排共存 左边是分屏浏览所指的首要列 在快捷指令中 那是驱动浏览的视图控制器 每当我们轻点其中一个单元格 右边的视图控制器就会发生改变 右边的视图控制器被称为次要列 让我们看看如何在代码中设置这个布局 首先 我们初始化一个分屏浏览控制器 在 iOS 14 中 我们可以访问带有样式的新初始化程序 该样式描述了 我们想在分屏浏览中显示多少列 我们希望布局有两列 所以我们将 doubleColumn 写入初始化器 如果我们想要有三列 我们只需写入一个 tripleColumn 样式 接下来 我们需要设置 将显示在每一列中的视图控制器 在首要列中 就是我们在左侧看到的那一列 我们想看到一个侧边栏 侧边栏 只是一个有一些特定样式的视图控制器 这就是我们的侧边栏视图控制器 我们会在首要列中使用它 我们通过对首要列调用 setViewController 来实现 然后是次要列 这个有点不同 因为我们希望它是动态的 每当我们轻点侧边栏中的一个单元格时 我们都希望更新次要列 因此 首先我们需要知道 何时选择该单元格以便我们对其做出反应 为此 我们遵循 UICollectionView 委托 并实施 didSelectItemAt indexPath 然后 我们通过调用 showDetailViewController 在次要列中显示 DetailViewController 因此现在 我们在首要列中有侧边栏视图控制器 在次要列中按需显示了细节视图控制器 这对 iPad 来说很棒 但我们也重新设计了 iPhone 的快捷指令 在那里 我们没有空间容纳两列 因此我们实施了一个完全不同的布局 在压缩宽度中 我们在列表视图中有一个标签栏 所以在标准宽度的侧边栏中的浏览选项 在压缩宽度中由标签栏和列表视图分担 现在 这是一个非常不同的布局 但我们在这里看到的 是使用我们刚才谈到的 UISplitViewController API 让我们看看它是如何实现的 除了首要列和次要列 UISplitViewController 还有一个紧凑列的概念 这是当设备处于压缩宽度时我们看到的列 就像其他列一样 我们只需调用 setViewController 来进行紧凑 紧凑布局就完成了 这真的很强大 因为我们可以自由地建立 自己单独的紧凑流程 但我们不需要担心在布局之间切换 所有这些都是由分屏浏览控制器完成的
使用这种方法需要知道的一点是 我们使用的是两个独立的视图层次结构 一个是标准宽度 另一个是紧凑宽度 因此 虽然分屏浏览控制器 知道应该根据当前的特质集合 使用哪种层次结构 但我们需要确保用户在尺寸类别变化时 处于正确的位置 让我们看一个例子 假设我们打开 app 并浏览到 Apple Watch 文件夹 然后我们决定并排打开另一个 app 这使得快捷指令 app 从标准宽度 移动到压缩宽度 我们什么都不用做 分屏浏览控制器 显示了压缩层次结构 这非常好 但这不是我们刚才浏览的层次结构 所以 默认情况下 它会让我们回到流程的起点 所以 我们需要确保这些转换是流畅的 我们是这样做的 根视图控制器 是分屏浏览控制器的父控制器 这是所有浏览发生的地方 每个可以在次要列中 显示的细节视图控制器 都符合一个协议 该协议要求视图控制器 提供一个方法来重新创建它 当尺寸类别即将改变时 我们查看当前的细节视图控制器 并使用协议方法重新创建它 一旦我们这样做了 我们就把它插入到新的视图层次结构中 这就是我们如何确保状态被恢复 让我们进一步讨论一下侧边栏 现在我们知道侧边栏只是一个 有一些特定样式的视图控制器 但让我们仔细看看 这个是侧边栏 你可以清楚地看到有一个大标题 一个让我们折叠侧边栏的左栏按钮 和一个切换编辑模式的右栏按钮 但是侧边栏里面有什么呢? 它是一个充满新列表单元格的集合视图 我们来看一下代码 首先是集合视图布局 侧边栏集合视图是使用默认配置的 组合式布局 最突出的是 sectionProvider sectionProvider 允许我们 配置集合中的每个部分 我们提供的部分 使用了 带有侧边栏外观的新 ListConfiguration 这基本上为我们设置了布局 该部分本身是一个新的列表部分 我们传入配置 然后就完成了 这是整个布局 现在让我们看一下单元格 首先 我们需要设置单元格 我们习惯于通过 在 collectionView 上调用寄存器 来注册单元格以便稍后退出队列 有了新的单元格注册 API 就有了一种新的方法 我们可以在一个地方以类型安全的方式 注册和配置单元格 我们不再需要担心跟踪 forUse 标识符 我们只需设置 cellRegistration 并将其直接写入到数据源中 这就是我们注册单元格的方式 让我们看看如何配置它们 在过去 无论何时我们想要 使集合视图单元格显得美观和有定制感时 我们都会创建一个子类 我们无需再这样做了 这要归功于 UIContentConfiguration API 我们可以混合和匹配配置 来获得我们想要的单元格 我们可以创建完全自定义的配置 或者我们可以利用现有的预制配置 例如 这里我们只是 使用预定义的 defaultContentConfiguration 这会返回 带有侧边栏单元格样式的默认配置 因为单元格 包含在带有侧边栏外观的列表中 我们只设置标题和图像 其他的都已经处理好了 这便是 iPad 上的快捷指令 优秀的 iPad apps 可以让用户充分利用绚丽的大显示屏 因此 尝试在你的 iPad app 中添加一个侧边栏 发挥创意吧 如果你的内容需要超过两列 使用一个补充列 使用具有预定义配置的集合视图 集合视图比表视图强大得多 预定义的配置 是向 app 添加功能和修饰的简单方法 最后 把界面去掉 依靠手势 让用户在你的 app 中自由移动 而不会被占用大量空间的模型打断 记得看看附在这个视频后的链接 关于这些新 API 还有很多东西需要学习 感谢收看 我们期待着看到你为 iPad 开发的 apps
-
-
1:57 - Create two column UISplitViewController
let splitViewController = UISplitViewController(style: .doubleColumn)
-
2:13 - Set view controllers for primary and secondary columns
splitViewController.setViewController(sidebarViewController, for: .primary) splitViewController.setViewController(myHomeViewController, for: .secondary)
-
2:28 - Create three column UISplitViewController
let splitViewController = UISplitViewController(style: .tripleColumn)
-
2:29 - Set view controller for supplementary column
splitViewController.setViewController(inboxViewController, for: .supplementary)
-
4:02 - Set view controller for compact column
splitViewController.setViewController(tabBarController, for: .compact)
-
5:29 - Set preferredSplitBehavior to .tile
splitViewController.preferredSplitBehavior = .tile
-
5:44 - Set preferredSplitBehavior to .displace
splitViewController.preferredSplitBehavior = .displace
-
5:51 - Set preferredSplitBehavior to .overlay
splitViewController.preferredSplitBehavior = .overlay
-
5:56 - Hide and show columns
splitViewController.hideColumn(.primary) splitViewController.showColumn(.supplementary)
-
6:08 - Set preferredDisplayMode
splitViewController.preferredDisplayMode = .oneBesideSecondary
-
8:06 - Collection view setup for sidebar list
let configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) let layout = UICollectionViewCompositionalLayout.list(using: configuration) let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
-
8:38 - Define a type for an example data structure
struct MyItem: Hashable { let title: String let image: UIImage }
-
9:36 - Create cell registration
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, MyItem> { cell, indexPath, item in var content = cell.defaultContentConfiguration() content.text = item.title content.image = item.image cell.contentConfiguration = content }
-
10:31 - Create diffable data source
let dataSource = UICollectionViewDiffableDataSource<Section, MyItem> (collectionView: collectionView) { collectionView, indexPath, item in return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) }
-
11:29 - Collection view setup for sidebar plain list
let configuration = UICollectionLayoutListConfiguration(appearance: .sidebarPlain) let layout = UICollectionViewCompositionalLayout.list(using: configuration) let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
-
15:35 - Example: Initializing UISplitViewController
let splitViewController = UISplitViewController(style: .doubleColumn) // Primary column let sidebar = SidebarViewController() splitViewController.setViewController(sidebar, for: .primary) // Secondary column func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { splitViewController.showDetailViewController(DetailViewController(), sender: self) }
-
17:50 - Example: Setting a view controller for compact width
let tabBarController = createTabBarController() splitViewController.setViewController(tabBarController, for: .compact)
-
20:39 - Example: Sidebar Collection View setup
let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider, configuration: UICollectionViewCompositionalLayoutConfiguration()) func sectionProvider(_ section: Int, environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection { var configuration = UICollectionLayoutListConfiguration(appearance: .sidebar) if (environment.traitCollection.horizontalSizeClass == .compact) { configuration.headerMode = .firstItemInSection } else { configuration.headerMode = .none } return NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: environment) }
-
21:13 - Example: Cell Registration
struct Section: Hashable { … } struct Item: Hashable { … } let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, indexPath, item in // Configure the cell } let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) }
-
21:48 - Example: Cell registration
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, indexPath, item in var content = cell.defaultContentConfiguration() content.text = item.title content.image = item.image cell.contentConfiguration = content }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。