自定义控件配置自定义属性

This article is originally published at https://swiftsenpai.com on August 9, 2020.

本文最初于 2020年8月9日 发布在 https://swiftsenpai.com 上。

In iOS14, Apple introduced the list layout in UICollectionView, allowing developers to easily create a list using UICollectionViewListCell — A collection view cell that comes along with iOS14 which provides list features and default styling.

在iOS14,苹果在推出了列表布局UICollectionView ,使开发人员能够轻松地创建使用列表UICollectionViewListCell -与iOS14提供列表功能和默认样式随之而来的,集视图单元格。

Even though UICollectionViewListCell is highly customisable, there are still situations where we might need to create our own custom cell in order to fit our app's requirements.

尽管UICollectionViewListCell是高度可定制的,但在某些情况下,我们可能仍需要创建自己的自定义单元格来满足应用程序的要求。

In this article, let’s look at how we can create a custom cell and use it alongside a custom content configuration to build a list in a UICollectionView.

在本文中,让我们看一下如何创建自定义单元格并将其与自定义内容配置一起使用,以在UICollectionView构建列表。

This is a continuation of my previous article “ Building a List with UICollectionView in Swift “. Therefore, if you are not familiar with building a list using a collection view, I highly recommend you check it out before proceeding.

这是我上一篇文章“ 在Swift中使用UICollectionView构建列表”的续篇 。 因此,如果您不熟悉使用集合视图构建列表,强烈建议您在继续操作之前先将其检出。

(The Sample App)

The following animated GIF showcases what we are trying to build in this article.

以下动画GIF展示了我们在本文中尝试构建的内容。





The sample app we going to build 我们将要构建的示例应用程序

As you can see, all the cells in the list have a layout that is different from the usual side-by-side image-text layout. Instead, they all have a custom top-bottom image-text layout.

如您所见,列表中的所有单元格都具有与通常的并排图像-文本布局不同的布局。 相反,它们都具有自定义的上下图像文本布局。

Furthermore, the appearance of the custom cells will change based on the state of the cell. When the cell is selected, its text will become red and the text’s weight will become heavy. The same goes for the symbol.

此外,自定义单元格的外观将根据单元格的状态而变化。 选中该单元格后,其文本将变为红色,并且文本的重量将变得heavy 。 该符号也是如此。

(The Concept)

Before we start implementing the custom cell, we must first understand what is content configuration, content view, and also the relationship between a custom cell, a content configuration, and a content view.

在开始实现定制单元之前,我们必须首先了解什么是内容配置内容视图 ,以及定制单元内容配置内容视图之间的关系。

A content view is a UIView subclass that conforms to the UIContentView protocol. It defines the layout and appearance of the custom cell. It is also in charge of displaying the correct data and appearance based on the provided content configuration.

内容视图是符合UIContentView协议的UIView子类。 它定义了自定义单元的布局和外观。 它还负责根据提供的内容配置显示正确的数据和外观。

A content configuration will be the content view’s view model and it conforms to the UIContentConfiguration protocol. On top of that, it is also in charge of generating a content view instance for the custom cell. Thus, you can treat it as a bridge that links up both content view and custom cell.

内容配置将是内容视图的视图模型,并且符合UIContentConfiguration协议。 最重要的是,它还负责为自定义单元格生成内容视图实例。 因此,您可以将其视为链接内容视图自定义单元格的桥梁。

A custom cell of a UICollectionView list is a subclass of UICollectionViewListCell. It has only 1 task - generate a properly configured content configuration object based on the state (selected, highlighted, disabled, etc.) of the cell and then assign the configuration to itself.

一的自定义单元格 UICollectionView列表的一个子类UICollectionViewListCell 。 它只有一项任务-根据单元的状态(选中,突出显示,禁用等)生成正确配置的内容配置对象,然后将配置分配给自身。

To summarize, the custom cell will create and assign a content configuration object to itself. The content configuration object will then generate a content view for the custom cell, and the content view will display the data provided by the content configuration object.

总而言之, 定制单元将创建一个内容配置对象并为其分配一个内容配置对象。 然后, 内容配置对象将为自定义单元格生成一个内容视图 ,该内容视图将显示由内容配置对象提供的数据。

Don’t worry if all these sound a bit confusing to you, I am sure things will clear up once we start looking into the sample code.

不用担心这些听起来是否会让您感到困惑,我相信一旦我们开始研究示例代码,一切都会清除。

(The Data Item Type)

For the sample app, we will reuse the data item type of my previous articleSFSymbolItem. As a recap, here's the definition of SFSymbolItem.

对于示例应用程序,我们将重用上一篇文章 SFSymbolItem的数据项类型。 回顾一下,这是SFSymbolItem的定义。


(Define Custom Content Configuration and Content View)

Let’s begin building our list by defining the custom content configuration and content view.

让我们开始通过定义自定义内容配置和内容视图来构建列表。

We will call our custom content configuration SFSymbolContentConfiguration and make sure it conforms to both UIContentConfiguration and Hashable protocol.

我们将自定义内容配置SFSymbolContentConfiguration ,并确保它既符合UIContentConfiguration又符合Hashable协议。


Next up, create a UIView subclass called SFSymbolVerticalContentView and conform it to the UIContentView protocol. This will be the content view of our custom cell.

接下来,创建一个名为SFSymbolVerticalContentViewUIView子类,并使它符合UIContentView协议。 这将是我们自定义单元格的内容视图。


(Custom Content Configuration Implementation)

With the SFSymbolVerticalContentView class definition in place, we are now ready to implement SFSymbolContentConfiguration.

有了SFSymbolVerticalContentView类定义之后,我们现在就可以实现SFSymbolContentConfiguration

As I mentioned before, the content configuration will act as the view model of the content view. Thus, let’s start by defining all the properties that will be consumed by the content view.

如前所述,内容配置将充当内容视图的视图模型。 因此,让我们首先定义内容视图将使用的所有属性。


After that, we will conform to the UIContentConfiguration protocol by implementing its method requirements:

之后,我们将通过实现UIContentConfiguration的方法要求来遵循它:


The content view instant return by the makeContentView() method will be used as the custom cell's content view. Therefore, its implementation is pretty straightforward, we just need to return an instance of SFSymbolVerticalContentView.

通过makeContentView()方法立即返回的内容视图将用作自定义单元格的内容视图。 因此,其实现非常简单,我们只需要返回一个SFSymbolVerticalContentView实例。


The 2nd method requirement — updated(for:) in charge of giving correct values to all the content configuration's properties that are not related to the cell's data items.

第二种方法要求- updated(for:) ,负责为与单元格数据项无关的所有内容配置属性提供正确的值。

Furthermore, the value will be assigned based on a given state. For our case, we only care about isSelected state and state other than isSelected. Following is the implementation of the method.

此外,将基于给定状态分配值。 对于我们的情况,我们只关心isSelected状态和状态比其他isSelected 。 以下是该方法的实现。


With that we have implemented a custom content configuration for our custom cell.

这样,我们为自定义单元实现了自定义内容配置。

(Custom Content View Implementation)

In this section, let’s implement the custom content view class SFSymbolVerticalContentView that we defined not long ago.

在本节中,让我们实现SFSymbolVerticalContentView定义的自定义内容视图类SFSymbolVerticalContentView


Let’s begin the implementation by defining the required UI elements. For the custom cell, we will need an UILable to display the SFSymbol name and an UIImageView to show the symbol image.

让我们通过定义所需的UI元素开始实施。 对于自定义单元格,我们将需要一个UILable来显示SFSymbol名称,并需要一个UIImageView来显示符号图像。


After that, it is time to conform to the UIContentView protocol. By looking at the documentation, there's only 1 property requirement to meet:

之后,是时候遵守UIContentView协议了。 通过查看文档 ,仅满足以下一项财产要求:


Here’s how we make SFSymbolVerticalContentView satisfy the requirement:

这是使SFSymbolVerticalContentView满足要求的方法:


In the above code, we define a variable named currentConfiguration of type SFSymbolContentConfiguration to store the content configuration being assigned to the content view.

在上面的代码中,我们定义了一个名为SFSymbolContentConfiguration类型的currentConfiguration变量,用于存储分配给内容视图的内容配置。

After that, we satisfy the UIContentView protocol requirement by defining configuration as a computed property, and use it to retrieve and set the value of currentConfiguration.

之后,通过将configuration定义为计算属性来满足UIContentView协议要求,并使用它来检索和设置currentConfiguration的值。

Do note that apply(configuration:) is a private function in charge of setting the value of currentConfiguration and applying all the currentConfiguration properties to the content view. We will implement this function in a bit.

请注意, apply(configuration:)是一个私有函数,负责设置currentConfiguration的值并将所有currentConfiguration属性应用到内容视图。 我们将稍后实现此功能。

Next up, we will work on the custom initializer init(configuration:) that we created during the definition of the SFSymbolVerticalContentView class.

下一步,我们将处理在SFSymbolVerticalContentView类的定义期间创建的自定义初始化程序init(configuration:)

We will perform 2 tasks during the initialization process — Setup the content view UI and apply the given content configuration to the content view.

在初始化过程中,我们将执行2个任务-设置内容视图UI并将给定的内容配置应用于内容视图。


And here are the implementations of the setupAllViews() and apply(configuration:).

这是setupAllViews()apply(configuration:)


The implementations of both of these functions are pretty much self-explanatory. The setupAllViews() function uses auto layout to add an UIStackView containing UILabel and UIImageView into the content view. On the other hand, the apply(configuration:) function applies all the given content configuration properties to the content view's UI elements.

这两个函数的实现几乎是不言自明的。 setupAllViews()函数使用自动布局将包含UILabelUIImageViewUIStackView添加到内容视图中。 另一方面, apply(configuration:)函数将所有给定的内容配置属性应用于内容视图的UI元素。

(Custom Cell Implementation)

The last part of the puzzle is to define a custom cell which is a subclass of UICollectionViewListCell so that we can display the content view inside an UICollectionView.

难题的最后一部分是定义一个自定义单元格,它是UICollectionViewListCell的子类,以便我们可以在UICollectionView内显示内容视图。

We will use the custom cell to keep track of the data item ( SFSymbolItem) currently being displayed. Therefore, let's create a custom cell class named SFSymbolVerticalListCell with a property named item of type SFSymbolItem.

我们将使用自定义单元格跟踪当前显示的数据项( SFSymbolItem )。 因此,让我们创建一个名为自定义单元格类SFSymbolVerticalListCell与属性命名的item类型SFSymbolItem


Prior to iOS14, a UICollectionView custom cell will need to take care of laying out cell UI, defining cell appearance, and displaying cell data. In iOS14, we have offset all of these tasks to the content configuration and content view.

在iOS14之前, UICollectionView自定义单元将需要布置单元UI,定义单元外观以及显示单元数据。 在iOS14中,我们将所有这些任务都抵消了内容配置和内容视图。

Therefore, there’s only 1 task left that needs to be handled by our custom cell — Assign itself a content configuration object based on the cell’s current state and data item.

因此,我们的自定义单元仅需要处理一项任务-根据单元的当前状态和数据项为其分配一个内容配置对象。

This can be easily achieved by overriding the updateConfiguration(using:) method of UICollectionViewListCell. This method will be triggered every time the state of a cell changes.

可以通过重写UICollectionViewListCellupdateConfiguration(using:)方法来轻松实现。 每当单元格状态更改时,都会触发此方法。


The code above is pretty straightforward, we generate a new content configuration object based on the cell’s current state, set the name and image to the object, and assign it to the cell.

上面的代码非常简单,我们根据单元格的当前状态生成一个新的内容配置对象,将名称和图像设置为该对象,然后将其分配给该单元格。

That’s it! We have finished implementing the custom cell.

而已! 我们已经完成了自定义单元的实现。

(Setting up Collection View)

With all the 3 main components (custom cell, content view, and content configuration) in place, we are now ready to put everything together to see them in action.

具备所有三个主要组件(自定义单元,内容视图和内容配置)后,我们现在可以将所有内容放在一起,以查看它们的实际效果。

The way of showing custom cells in a collection view is very similar to how we show the standard UICollectionViewListCell in a collection view. I won't go in-depth into this as it has been covered in my previous article.

在集合视图中显示自定义单元格的方式与在集合视图中显示标准UICollectionViewListCell方式非常相似。 我不会在前一篇文章中对此进行深入探讨。

However, one thing to note is that we must register the SFSymbolVerticalListCell to the collection view. On top of that, within the cell registration handler, we only need to set the data item to the cell and let the cell's updateConfiguration(using:) method to take care of assigning the content configuration object to the cell.

但是,要注意的一件事是,我们必须将SFSymbolVerticalListCell注册到集合视图。 最重要的是,在单元格注册处理程序中,我们只需要将数据项设置为该单元格,并让该单元格的updateConfiguration(using:)方法负责将内容配置对象分配给该单元格。


Here’s the full viewDidLoad() method of our view controller.

这是我们视图控制器的完整viewDidLoad()方法。


Phew… We have written quite a lot of code! Let’s build and run the sample project to see everything in action.

ew ...我们编写了很多代码! 让我们构建并运行示例项目以查看所有操作。

(Changing Cell’s Background Color)

When you are playing around with the sample app, you should notice that the cell’s background will become gray when it is selected.

当您在使用示例应用程序时,您应该注意到选中该单元格的背景将变为灰色。


Custom cell’s background color when selected

选定时自定义单元格的背景色

This is certainly not what we want! How should we change the cell’s background color when it is selected? Luckily Apple introduced a new class called UIBackgroundConfiguration that works similarly to the UIContentConfiguration.

这当然不是我们想要的! 选中单元格时,应如何更改其背景颜色? 幸运的是,Apple引入了一个名为UIBackgroundConfiguration的新类,该类与UIContentConfiguration相似。

With that in mind, let’s head back to the SFSymbolVerticalListCell's updateConfiguration(using:) method and set the cell background configuration accordingly.

考虑到这一点,让我们回到SFSymbolVerticalListCellupdateConfiguration(using:)方法,并相应地设置单元格背景配置。


If you would like to have more control over the UIBackgroundConfiguration 's behavior, you can definitely create a custom background configuration class. However, that will be a story for another day.

如果您想对UIBackgroundConfiguration的行为进行更多控制,则可以肯定地创建一个自定义后台配置类。 但是,这将是另一天的故事。

(Wrapping Up)

Creating custom UICollectionViewListCell using custom content configuration is a fairly new concept in iOS development and you might find it a little bit confusing at first.

在iOS开发中,使用自定义内容配置创建自定义UICollectionViewListCell是一个相当新的概念,一开始您可能会感到有些困惑。

To sum up what we have learned in this article:

总结一下我们在本文中学到的知识:

  1. The content configuration will act as the view model of the content view. Furthermore, It is also in charge of defining the cell’s appearance in various states.
  2. The content view takes care of the custom cell’s UI. It consumes all the content configuration properties and sets them to the respective UI elements.
  3. The custom cell in charge of setting all the data item properties to the content configuration object and assigning it to the cell’s contentConfiguration property.
    定制单元负责将所有数据项属性设置为内容配置对象,并将其分配给单元的contentConfiguration属性。

Feel free to download the full sample project from Github if you need any references.

如果需要任何参考,请随时从Github下载完整的示例项目。

I will try to cover some other topics such as custom background configuration, multi-section list, and expandable cells in the near future.

我将在不久的将来尝试涵盖其他一些主题,例如自定义背景配置,多节列表和可扩展单元。

If you would like to get notified when I publish new articles related to these topics, feel free to follow me on Twitter or Medium.

Thanks for reading. 🧑🏻💻

谢谢阅读。 💻