UIKit 新进展:现代 Cell 配置

Python实战社群

Java实战社群

长按识别下方二维码,按需求添加

扫码关注添加客服

进Python社群▲

扫码关注添加客服

进Java社群

作者:VincentMing,iOS开发,现在字节跳动剪映团队搬砖

Session:https://developer.apple.com/videos/play/wwdc2020/10167/

iOS14 给 UICollectionView 带来了全新的特性,可以大致分为三类:如何生成数据,如何定义布局以及如何显示内容。

本文会着重讲述视图配置,包括用于给 cell 配置内容和定义样式的新 API。

首先来看看 iOS13 时我们是如何配置 TableView 的 cell:

在 iOS14 中我们通过下面的方式进行 cell 配置:

两者看起来挺相似的,只多了两行代码,我们仔细对比下。

第一件事是获取 cell 的默认内容配置,它总返回一个全新的配置,没有任何自定义的内容,但它拥有基于 cell 和 TableView 的默认样式。关于样式我们后续会展开讲。当下,我们只把图片和文字传入内容配置中。这一段和 iOS13 的做法很相似。最后一步,我们把刚才的配置传给 cell 的 contentConfiguration 属性。只要完成这一步, cell 就会更新并显示我们配置的图片和文字。而在这之前,所有对图片和文字的改动只影响存储在 content 变量中的配置副本。因为我们使用内容配置,所以我们从未直接碰触 UI 组件,如 ImageView 或 Label。所有的属性是在配置上操作的。

使用内容配置来管理 cell 有什么好处呢?其一就是,我们配置 TableViewCell 的代码和配置 CollectionViewCell 的代码是一样的。实际上,同样的代码可以用于任何视图,哪怕不是 cell,如 TabelView 的 header 和 footer。这是如何做到的?因为配置是可组合的。不像 UITableviewCell 那样把全部功能固化在 cell 类中,这些标准 cell 布局和外观作为独立的部件提供,可以直接插入支持它们的任何 cell 或视图中。

下图是使用 iPad 新边栏的应用截图,边栏的 cell 使用了相同的内容配置,但处于不同的状态,如正常态、选中态、高亮态、禁用态等。可以看出,这些 cell 的默认样式在不同状态下各不相同。通过使用配置来设置我们的 cell,可以自动获得所有这些不同的外观。

我们稍后将详细讨论其工作原理。至此我们已经领略了这些新配置,但是它们到底是什么?

什么是配置(Configuration)?

  1. 配置描述了视图在某种特定状态下的外观,如内容,样式,指标和行为等。

  2. 配置只是一堆属性,只有将其应用于视图或cell并进行渲染,它们才会生效。

  3. 配置是可组合的,可用于任何支持它们的cell或视图。

目前有两种类型的配置:背景配置和内容配置。

背景配置有许多属性,能够快速指定常见的背景外观,如自定义背景填充色,设置模糊效果,设置描边和圆角。也可以通过提供自定义视图实现定制的效果。

列表内容配置不仅能为 cell、header、footer 提供标准布局(类似于 UITableViewcell 的样式),还支持图片、文字、可选的二级文字,以及许多属性可供自定义配置,还提供了更高级的特性,如灵活的布局以支持大量文字的显示,特殊的布局模式以支持辅助功能下的可变大小文字。

这两种配置类型具有一些共同的设计原则。

最重要的原则之一是配置的轻量化,创建成本很低。它们是值类型,这意味着这个配置只属于你,你对配置所做的更改不会影响其他任何事情,除非你把配置应用到cell。

因为其轻量化,你应当总是创建一个全新的配置,例如获取 cell 的默认内容配置,无论是第一次配置 cell 还是后续更新 cell。使用配置时,你无需考虑过去的状态,也不必先拿到已有的配置再去修改它。每次都从全新的配置开始,修改好后应用到 cell。

这个工作流和以往的 UIKit 有所不同,但它其实彻底解放了开发者,它会自动查明哪些视图改变了,并高效地去更新,而无需开发者的介入。

配置不仅提供了针对大量状态的默认外观,而且基于健壮的底层机制,让开发者可以对各种状态定制外观。配置还提供了很多高级行为,只需要几行代码即可实现。比如想对背景做动画,只需在动画中设置新的背景配置即可。

配置不仅易用,而且其设计方式杜绝了一整个类型的 bug,尤其是在处理复杂的状态和转换时。当前应用的配置就是事实,且当应用新配置时,新配置会全部同时生效。

最后,配置是为性能而生的,这对确保平滑滚动尤为重要。因为 UIKit 负责管理视图和渲染,所以我们能够实现许多内部性能优化。

配置状态

配置状态表示用于配置 cell 和视图的各种输入。

UITraitCollection 中的 Trait 是确定如何设置视图的最常见输入之一。如 layout direction、size class、user interface style 等。

在 Trait 之上,cell 和视图还拥有各种状态,如选中态,或是作为拖拽操作的目标,或是临时被禁用。在这些状态之上,你的应用程序还拥有自定义状态。如通信软件需要知道一个消息是已归档还是已标记,而支付软件可能会显示哪个交易正在进行中。如果使用viewModel管理单元格,也可以将该viewModel视为自定义状态。各种状态如下图所示:

所有这些构成配置状态:一个各种特征、状态和用户自定义状态的集合。

那么您在哪里找到配置状态?集合或表视图中的每个单元格,页眉和页脚都有其自己的配置状态。如下图所示,有三个 cell,每个 cell 可能有不同的配置状态。

那么配置状态是什么样的呢?这里可以看到有两种配置状态:view 配置状态和 cell 配置状态。可以看到,view 配置状态有 Trait 集合,高亮选中等状态,以及自定义状态。

cell 配置状态除了包括上述状态,还有直属于 cell 的状态,如编辑、滑动、展开和拖拽。

更新配置

使用配置状态的重要操作之一是更新配置。

你可以根据不同的配置状态获得新的背景配置或内容配置,它是一个属性已经更新到最新状态的配置副本。当您请求更新的配置时,原始配置不会更改。并且,如果您在原始配置上自定义了任何属性,则这些属性在更新后的配置上将保持不变。属性设置好了后,就像被锁定了一样。

回顾之前的演示,可以看到内容配置会根据不同状态更新外观,这是因为有自动配置更新。默认情况下,当你对 cell 设置了背景或内容配置时,只要其配置状态发生变化,就会自动更新该配置,并将新配置应用于 cell。下图中的这些属性可以控制自动更新行为。

如果你希望获得各种状态的默认样式,那么使用自动更新即可。如果要自定义不同状态的外观,则可以禁用自动更新并手动更新配置。但是更新配置的代码应该写在哪里呢?我们在 CollectionView 和 TableView 的 cell 上新增 updateConfiguration(using state: UICellConfigurationState) 方法。你需要在 cell 的子类中重写该方法,根据传入的配置状态来更新 cell 的外观。该方法总是在 cell 被首次显示之前调用,且只要配置状态更改,就会再次调用此方法,使得 cell 一直处于最新状态。

当使用配置时,无需担心旧状态。每次只需获取新的配置,设置其属性,然后将其应用于 cell 即可。当代码中只有一处可以更新配置并将其应用到 cell 时,配置才能发挥最佳作用。如果你使用的是自定义 cell 子类,则 updateConfiguration(using state: ) 方法是执行上述操作的最佳选择,同时也最适合集中处理任何其他设置或更新。

例如,如果你使用的是最新的 CollectionViewListCell,则可以通过此方法为不同状态更新 cell 附件的 tint 颜色。如果需要重新配置单元,只需调用 setNeedsUpdateConfiguration() 方法。

让我们看一个示例,如何使用该方法设置 cell 并手动更新不同状态的配置。首先通过 cell 的默认内容配置获得全新的配置,然后将其更新到新的状态,这将为我们提供新状态的系统默认样式配置。然后我们根据 cell 将要显示的内容设置配置的图像和文本。接下来准备应用自定义属性。检查当前状态是突出显示还是选中,如果是,则将图像和文本颜色设置为白色。对于其他任何状态,我们没有设置颜色,即使用了配置的默认颜色。最后,我们把新配置应用到 cell。每当状态变更,都会再次调用此方法,并为新状态应用新配置。这就是自定义不同状态下外观的内容配置的方法。

我们同样可以在此处自定义背景配置。在此示例中,我们为某些状态下的图像和文本设置了不同的颜色。但还有另一种方法,可以使用一种称为“颜色转换器”的新类型来更改不同状态下的颜色外观。彩色转换器接受一种颜色,再以某种方式修改颜色并返回。

例如某个颜色转换器可以返回任意颜色的灰度。因此,颜色转换器只是简单的函数映射,但它却非常强大,因为你可以使用不同的颜色转换器把同一个颜色转换成不同的颜色。这就是通过颜色转换器为不同状态创建不同外观颜色的方法。某些样式和状态的某些默认配置将具有预设的颜色转换器,以便为该状态生成特定的外观。变色器与输入颜色结合使用,可以产生你需要的颜色。

需要注意的细节

知道了如何通过配置为不同状态生成新的外观之后,我们来了解下使用背景和内容配置时需要注意的一些细节。CollectionView 的 ListCell,TableView 的 cell、header 和 footer 都能根据包含的 List 或 TableView 的样式自动设置其默认的背景配置。因此通常情况下,你无需做任何事就能获得想要的背景样式。

内容配置则与此有所不同。cell 不会自动应用一个内容配置,而你可以对 cell 使用 defaultContentConfiguration 方法来获得基于 cell 当前样式的全新配置,就像前面例子那样。对于背景配置或内容配置,你可以通过 UIBackgroundConfiguration 和 UIListContentConfiguration 轻松获得任意样式下的默认配置。

再来看个侧边栏列表的例子。如图所示,所有的 cell 都具有与侧边栏样式相匹配的默认背景和内容配置。当选中某一个 cell 时,背景样式和内容样式会随之改变。

同样的列表,可以使用不同的样式,如分组外观、内嵌分组外观、普通外观等。这些外观和 UITableView 中的很相似。collectionView list 支持新的外观,如两种侧边栏样式。

上述的所有不同列表外观来自默认的背景和内容配置。

默认配置还支持动态大小,如下图所示。

当使用 accessibility 最大字号时,特殊的 cell 布局使得文字会围绕图片显示,来最大化利用空间。内容配置从底层向上,支持这样的动态布局。

我们来快速了解一下其底层实现机制。内容配置适用于自调节大小的 cell,其高度可以根据具体配置和环境灵活调整。这有助于你的应用在不同尺寸的设备、不同的动态大小下展示不同数量和类型的内容时都能好看。

通过内容配置,可以控制下图中蓝色的 margin 和橙色的 padding 属性。这些属性和实际展示内容一起决定了固有高度,影响 cell 如何自调整大小。因此,你不该使用固定高度,而应该通过使用这些属性让 cell 自动调节大小。

您还应该了解另一种布局概念。

如上图所示,当更换了不同宽度的图片时,原本对齐的列表变得不对齐了,因为图片是左对齐的,且每行文字和图片之间有同样的间距。

解决的方法是设定每个图片的保留大小(红线之间),再让图片在保留区域水平居中。如果图片比保留大小更大,则允许其从保留区域伸展出来。文字也对齐了,因为它们与图片的保留区域末端保持相同的距离。

如果你使用 Symbol 图片,UIKit 已经帮你应用了标准保留大小;对于其他图片,你可以自行设置其保留大小。

其他值得注意的点

配置和一些已有属性是互斥的。如应用背景配置总会重置背景颜色,且置空背景视图属性,反之亦然。所以你不能把背景配置和其他设置背景属性的代码混用。特别是使用 UITableView。

内容配置则取代了 cell、header 和 footer 的内置子视图,如图片、文本标签、详细文本标签等。这些老的内容属性会在未来的版本被弃用。我们鼓励你使用内容配置以获得强大的特性和可定制性。

除了列表内容配置,你还可以使用 ListContentView,用配置创建或更新该视图,再把它和你的自定义视图组织到一起。

ListContentView 只是普通的 UIView,你可以在任意地方使用它,即使不在 CollectionView 或 TableView之中,如在 UIStackView 中使用。

即使你在 cell 中打造一个完全自定义的视图结构,系统配置仍然能帮到你。因为配置非常轻量化,你可以把它用作字体、颜色、间距的默认值拷贝到自定义视图,哪怕你从不直接应用该配置。

对于更高阶的使用场景,你可以创建一个完全自定义的内容配置类型,以及渲染它的内容视图类,然后就像使用列表内容配置一样去使用你的自定义配置。使用自定义配置,可以充分利用前面提到的所有特性,包括允许自定义配置自动更新到新的状态。不管你的 cell 多么复杂,你都能从强大的配置中受益。

以上就是现代 cell 配置的全部基础内容了。

总结

总结一下,背景配置和内容配置非常易用,你可以用同样的代码去配置 CollectionView cell 或 TableView cell。

配置让你专注于你想展示什么,而不必操心于如何更新所有的视图。

每次都从全新的配置开始,设置成想要的样子,应用到 cell,让 UIKit 去代劳剩下的一切。

你已经知道如何使用配置状态去更新配置,从而生成一系列不同的样式。

你可以利用配置状态去设置 cell。

今天讲到的一切从设计层面具有可组合性和可扩展性,便于满足你的需求。去下载样例工程尝试新的 API 吧。

程序员专栏 扫码关注填加客服 长按识别下方二维码进群

近期精彩内容推荐:  

 程序员写的这一行代码,被国家博物馆收藏了

 2020 年 9 月程序员工资统计,我扯后腿了~

 提高国内访问 GitHub 的速度的 9 种方案

 Python是强类型语言,还是弱类型语言?

在看点这里好文分享给更多人↓↓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值