UICollectionViewLayout分步指南

如果您刚开始学习iOS编程时间不长,我相信大多数人会建议您不要过多了解UICollectionViewLayout,因为UICollectionViewFlowLayout在大多数情况下将足以满足您的需求。

提出此类建议的原因很简单: UICollectionViewLayout可能相当复杂。 但是,不要让世界“复杂化”,使您害怕。 UICollectionViewLayout可能很复杂,但绝对不难

您需要至少了解以下主题才能理解该指南

  • CollectionView(委托和数据源)

本质上, UICollectionViewLayout只是一个类对象,负责安排UICollectionView的子视图。 但是在UICollectionView的世界中,我们将子视图称为Cell,并通过一个名为UICollectionViewLayoutAttributes的包装器类来设置视图 每当设置UICollectionViewLayoutAttributesframe属性时,实际上就是在设置单元格的框架

除了框架外,UICollectionViewLayoutAttributes中还有其他属性。 但是在学习完本教程之后,您无需我过多解释,就应该了解如何使用它们。

3.1添加四个盒子

如果我要您在视图控制器的主视图上添加四个框,以使它们的排列完全如下面的图1所示

您将如何以最野蛮,最优雅的方式来做?

我认为我们大多数人都会或多或少地提出以下相同的代码

但是现在,如果您真的考虑我们添加到主视图中的四个框,那么设计或布局是否UICollectionView如何在UICollectionViewLayoutUICollectionViewFlowLayout的情况下如何布局四个相同大小的单元格相似

唯一的区别是,如果我们要在主视图中添加更多框,则需要手动为所有添加的框编写代码(初始化和位置代码),而对于UICollectionView,它将仅自动布局添加的框盒子(或单元)以相同的方式,但不再需要初始化和位置代码

初始化代码位于cellForItem数据源方法中,而位置代码位于UICollectionViewLayout类中。

那有什么收获呢? 需要注意的是, UICollectionViewFlowLayout必须包含一个通用函数,该函数能够正确计算其子视图(单元)的位置,而不管这些子视图有多少个。 因此,如果我们要自己编写一个UICollectionViewFlowLayout类,我们要做的就是概括这些框的放置方式并编写一个函数以产生子视图的这些位置代码。

就是说,如果我们能够编写一个函数来概括如何将框放置在主视图中的模式,那么我们可以在主视图中获得与具有UICollectionViewLayout的UICollectionView相同的结果。

如果现在将这段代码粘贴到视图控制器中,则可以指定要在主视图中显示的任意数量的框,它们的布局就像在UICollectionViewFlowLayout的集合视图中一样。

3.2结论

UICollectionViewLayout不是神奇的对象,它的作用实际上非常简单。 它仅提供一种通用方法来计算CollectionView的子视图(单元)的位置。

就像将addBoxes(_ number)函数中的代码重构为一个单独的类一样。 这就对了。

我一直在谈论UICollectionViewLayout,但以UICollectionViewFlowLayout为例。 因此,在出现任何混乱之前,我只想指出两者之间的区别,或者更确切地说,是两者之间的联系。

UICollectionViewFlowLayout是UICollectionViewLayout的子类。 好? 但这实际上是什么意思?

作为超类的UICollectionViewLayout仅仅是一个骨架,要求我们遵循放置和检索位置代码的方式。 它具有三个功能一个属性来安排位置代码。

  1. Prepare()—函数
  2. CollectionViewContentSize —属性
  3. layoutAttributesForElements(矩形)
  4. layoutAttributesForItem(位于indexPath处)

UICollectionViewLayout中 ,所有这些功能和属性均不起作用。 例如,layoutAttributesForElements(in rect)在UICollectionViewLayout中返回nil。 UICollectionViewLayout正在等待有人对其进行子类化并提供适当的内容。

UICollectionViewFlowLayoutUICollectionViewLayout的具体类,已实现所有四个成员 ,以这种方式将单元以网格的方式排列。

现在,如果我已经说服您UICollectionViewLayout一点都不困难,那么我们就可以开始实现自定义流程布局了。 但是,我没有实现幻想的布局,而是要重新实现UICollectionViewFlowLayout

为了向您展示Apple工程师实现的UICollectionViewFlowLayout中可能的下划线代码。

5.1委托获取大小的方法

在我们真正开始实现UICollectionViewLayout之前,我们需要定义一些协议来获取所需的数据。 在这种情况下,单元的大小。

您可以看到UICollectionViewDelegateFlowLayout也有几个委托方法来获取其布局所需的数据。 在原始的UICollectionViewFlowLayout中,当我们设置CollectionView的委托时,iOS会自动帮助我们将CollectionView的委托设置为其FlowLayout的委托。

但是由于我们无法访问UICollectionView的基础代码,因此我们在ViewController中手动设置了CustomCollectionViewLayoutDelegate

在开始实现Prepare()之前,让我们为CustomCollectionViewLayout类定义一些属性

这是不言自明的,因此我将不解释代码。

5.2准备()

这是在其他所有函数之前调用的函数。 这是您的位置代码应去的地方。 您需要在这里做两件事。

  1. 计算UICollectionView的contentSize
  2. 计算每个单元格的位置。 (这将包装在UICollectionViewLayoutAttributes中

Prepare()是我进行所有计算并将单个单元格的属性放到属性缓存中以在需要时进行检索的地方。

5.3 LayoutAttributesForElement和layoutAttributesForItem

prepare()函数之后,其余部分就变得微不足道了。 从某种意义上说,我们需要做的就是访问缓存以获取我们需要的相应UICollectionViewLayoutAttributes

现在,如果您在viewController中设置了一个collectionView并将其UICollectionViewLayout设置为CustomCollectionViewLayout,您将能够看到这些框以网格方式进行布局(将单元格的backgroundColor设置为随机颜色以查看结果)。

6.额外注意事项

在此示例中,我没有包括UICollectionViewFlowLayout之类的填充,插图和其他内容。 但是,如果您能够掌握要点。 对于您来说,添加诸如minimumLineSpacingminimumIterItemSpacing之类的属性以及所有这些内容应该相当简单。

7.结论

希望我在解释UICollectionViewLayout并减轻您对此的恐惧方面做得还不错。

干杯。