UICollectionViewLayout

父类:NSObject

UICollectionViewLayout是抽象基类,你可以使用它的子类来生成对collection view的布局信息。布局layout)对象的工作是决定在collection view的边界内如何放置cellsupplementary view以及decoration view,并且当collection view想要获取这些布局信息时能够报告给collection viewcollection view会根据提供的布局信息来显示对应的视图view),以便将视图展现在屏幕上。

一、概述

你必须创建UICollectionViewLayout类的子类才能使用它。在你考虑要创建UICollectionViewLayout类的子类之前,你应该先查看UICollectionViewFlowLayout,看看这个是否符合你的布局需要。

1. 子类提示

布局对象的主要工作是提供collection view中每一个Item的位置和视觉状态信息。布局对象不会根据他自己提供的布局信息来创建视图。这些视图会被collection view的数据源来创建。相反,布局对象根据布局的设计定义基础元素的位置和视觉大小。

collection view有三种需要被设置的视觉元素:

  • Cells——被布局放置的主要元素。每一个cell代表了collection view中的一项数据。一个collection view可以有一组cell,并且它还可以将这些cell分在不同的section中。布局对象的主要工作是在collection view的内容区域排列这些cell
  • Supplementary views——也可以显示数据,但是和cell有区别。与cell不同,Supplementary view不可以被用户选择。反而你可以使用Supplementary view来填充section或者整个collection view的的头部视图header view)和尾部视图footer view)。Supplementary view是可选的,并且它们的也是通过布局对象来使用和放置。
  • Decoration views——是在collection view不可以被选择的也不可以绑定数据的只能够看的装饰。Decoration view可以说是其他类型的Supplementary view。和Supplementary view一样,Decoration view是可选的,并且也是通过布局对象来使用和放置。

collection view要求它的布局对象在许多不同的时间为这些元素提供布局信息。每一个cell视图都使用布局对象提供的安置信息显示在屏幕上。类似的,每次元素从collection view中插入或删除都会产生额外的布局。collection view总会将布局限制在屏幕上显示的对象上。

2. 重写的方法

每一个布局对象都应该实现下面的方法:

  • @property(nonatomic, readonly) CGSize collectionViewContentSize;
  • - (NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
  • - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
  • - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;(如果你的布局支持Supplementary view。)
  • - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;(如果你的布局支持Decoration view。)
  • - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

这些方法提供了collection view需要在屏幕上放置内容的基本布局信息。当然,如果你的布局不支持Supplementary view或者Decoration view,就不需要重写对应的方法。

collection view中的数据改变或者collection viewItem被插入或删除的时候,collection view会告知它的布局来更新布局信息。具体的来说,任何一个Item被移动、添加或者删除,它的布局信息都必须更新以反映他的最新位置。对于已经移动的Item来说,collection view会使用标准方法来重载Item的更新布局属性。对于将要插入或删除的Item来说,collection view调用一些不同的方法,这些方法你需要重写来提供适当的布局信息:

  • - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
  • - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
  • - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
  • - (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
  • - (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
  • - (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;

除了这些方法,你也可以重写- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法做与任何一个布局有关的准备。你也可以重写- (void)finalizeCollectionViewUpdates;方法并用它来添加动画或者处理任何最终布局相关的任务。

3. 使用无效上下文优化布局性能

当你开始设计的自定义布局的时候,你可以使用你布局中确实改变的已经变为无效的部分来提高你的布局的性能。当你改变了一些Item,调用invalidateLayout方法强制使collection view重新计算所有布局信息并展示它。一个更好的解决办法是只计算改变部分的布局信息。一个无效上下文会告诉你那个部分的布局改变了。布局对象可以使用这些信息来减少需要计算的数据量。

想要自定义一个你布局中的无效上下文请使用UICollectionViewLayoutInvalidationContext的子类。在你的子类中定义自定义属性,这个属性是你布局数据中可以被独立重新计算的部分。当你想要在运行时中使你的布局无效,创建一个你的无效上下文子类的实例,基于改变的布局信息配置自定义属性,然后把这个实例传入到你的布局- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context;方法中。你的自定义实例对于这个方法可以实现使用无效上下文的信息只计算你的布局改变的部分。

如果你为你的布局对象自定义了一个无效内容子类,你也需要重写@property(class, nonatomic, readonly) Class invalidationContextClass;方法并且返回你的自定义类。collection view总会在它需要一个无效上下文时创建一个你指定的类。在这个方法中运行你的自定义子类,来确保你的布局对象总有它期望的无效上下文

二、内容

1. 获取collection view信息

@property (nullable, nonatomic, readonly) UICollectionView *collectionView;

当前正在使用这个布局对象的collection view对象。
当一个新的布局对象被分配给一个collection view对象时,这个collection view对象会设置这个布局对象的这个属性。

@property(nonatomic, readonly) CGSize collectionViewContentSize;

返回collection view的内容部分的宽度和高度。
子类不许重写这个方法,并且使用它来返回collection view的内容部分的宽度和高度。这个值表示所有内容的宽度和高度,不仅仅是当前可见内容的高度。collection view使用这个信息来配置他自己的可以滚动的内容部分的大小。
这个方法的默认实现将会返回CGSizeZero

2. 提供布局属性

@property(class, nonatomic, readonly) Class layoutAttributesClass;

返回用来创建布局属性对象的类。
如果你的UICollectionViewLayoutAttributes的子类为了管理额外的布局属性,你需要重写这个方法并返回他自己的自定义子类。当创建新的布局属性对象时这个方法使用这个类创建布局属性。
这个方法只会用到这个子类,而不会调用你的代码。

- (void)prepareLayout;

告诉布局对象来更新当前布局。
布局第一次更新collection view展示的内容,以及无论何时布局因为视图的改变而失效时。在每次布局更新过程中,collection view都会首先调用这个方法来让你的布局对象有机会对即将到来的布局操作做准备。
这个方法的默认实现不做任何事情。子类可以重写这个方法用来设置数据结构或执行任何在之后布局中需要的初始计算。

- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;

返回所有cell视图在指定范围内的布局属性
子类必须重写这个方法,并且使用这个方法返回给定范围与视图相交部分的所有Item的布局信息。你的实现需要返回所有可见元素,包括cellSupplementary viewDecoration view属性
当创建布局属性,总会创建一个代表了合适的元素类型(cellSupplementary view或者Decoration view)的属性对象。collection view区分每个类型的属性的不同,并且使用这些信息来决定要创建哪些视图以及如何管理它们。

- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

返回给定索引值指定的Item布局属性
子类必须重写这个方法,并且使用这个方法返回collection view中的Item的布局信息。你使用这个方法只提供响应的cell的布局信息。这个方法不支持Supplementary viewDecoration view

- (UICollectionViewLayoutAttributes *)layoutAttributesForInteractivelyMovingItemAtIndexPath:(NSIndexPath *)indexPath withTargetPosition:(CGPoint)position;

返回用户交互时移动的Item布局属性
当一个Item因为用户交互而移动时,这个布局对象使用这个方法获得这个Item在指定位置的布局属性。这个方法的默认实现返回这个Item的当前属性的有两个改动的副本:center点被设置为当前位置的值,zIndex值被设置为NSIntegerMax,并使这个Item漂浮在collection view中的其他Item的上方。
子类可以重写这个方法修改额外需要的布局属性。如果你重写这个方法,首先调用super获取Item的当前属性,然后返回值做你的更改。

- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;

返回给定的Supplementary View布局属性
如果你的布局对象定义来任何的Supplementary View,你必须重写这个方法,并且使用这个方法返回这些视图的布局信息。

- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;

返回给定的Decoration View布局属性
如果你的布局对象定义来任何的Decoration View,你必须重写这个方法,并且使用这个方法返回这些视图的布局信息。

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset;

返回动画布局更新或改变后使用的content offset
布局更新过程中,或者在两个布局的过渡过程中,collection view会调用这个方法让你有机会改变动画结束时建议的content offset。如果动画或者过度可能导致Item被放置的方法不符合你的设计要求,那么你可以重写这个方法。

collection view会在调用- (void)prepareLayout;以及@property(nonatomic, readonly) CGSize collectionViewContentSize;之后调用这个方法。

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
  • proposedContentOffset CGPoint - 停止滚动的建议位置点(在collection view的内容区域中)。这个值如果没有调整将是自然停止的点。这个点指的是可见区域的左上角的点的坐标。
  • velocity CGPoint - 沿着水平或垂直滚动的当前速度。这个值表示的是每秒滚动的点的数量。

返回滑动结束的点。
如果你想要滑动行为对齐到指定的边线,你可以重写这个方法,并且使用这个方法改变将要停止的位置点。例如,你可以使用这个方法让滑动停止在两个Item之间的分界线上,而不是停止在一个Item的中间。

3. 响应Collection View更新

- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;

通知布局对象,Collection View的内容将要更新。
Item被插入或删除时,Collection View会通知它的布局对象,以便它可以根据需要调整布局。过程的第一步事调用这个方法使布局对象知道预计的改变。之后,继续调用收集整个Collection View中将要将要有插入,删除和移动动画的Item的布局信息。

- (void)finalizeCollectionViewUpdates;

Collection View更新期间执行任何额外动画或者清理所需。
Collection View调用这个方法作为之前动画在当前位置改变的最后一步。这个方法在动画的block里面被调用,用来执行所有插入,删除和移动动画,所以你可以使用这个方法创建需要的额外动画。或者,你可以使用它来执行任何与管理你的布局对象的状态信息相关的最后一分钟任务。

- (NSArray<NSIndexPath *> *)indexPathsToInsertForSupplementaryViewOfKind:(NSString *)elementKind;
  • elementKind NSString - 给定Supplementary View的类型。

返回你想要添加到布局中的Supplementary View对应的索引组成的数组。如果你不想添加任何Supplementary View,请返回空数组。
无论你添加cell还是sectionCollection View中,Collection View都会调用这个方法。实现这个方法让你的布局对象有机会添加新的Supplementary View
Collection View在调用- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;- (void)finalizeCollectionViewUpdates;方法之间调用这个方法。

- (NSArray<NSIndexPath *> *)indexPathsToInsertForDecorationViewOfKind:(NSString *)elementKind;
  • elementKind NSString - 给定Decoration View的类型。

返回你想要添加的Decoration View对应的索引组成的数组。如果你不想添加任何Decoration View,请返回空数组。
无论你添加cell还是sectionCollection View中,Collection View都会调用这个方法。实现这个方法让你的布局对象有机会添加新的Decoration View
Collection View在调用- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;- (void)finalizeCollectionViewUpdates;方法之间调用这个方法。

- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;

返回一个Item插入到Collection View中开始的布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Item被插入之前都会调用。
你的实现需要返回描述了Item的最初位置和状态的布局信息。Collection View使用这个信息作为动画的开始位置。(动画的终点位置是这个ItemCollection View中的新位置。)如果你返回nil,那么Item会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil

- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;

返回一个Supplementary View插入到Collection View中开始的布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Supplementary View被插入之前都会调用。
你的实现需要返回描述了Supplementary View的最初位置和状态的布局信息。Collection View使用这个信息作为动画的开始位置。(动画的终点位置是这个Supplementary ViewCollection View中的新位置。)如果你返回nil,那么Supplementary View会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil
.

- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;

返回一个Decoration View插入到Collection View中开始的布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Decoration View被插入之前都会调用。
你的实现需要返回描述了Decoration View的最初位置和状态的布局信息。Collection View使用这个信息作为动画的开始位置。(动画的终点位置是这个Decoration ViewCollection View中的新位置。)如果你返回nil,那么Decoration View会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil

- (NSArray<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind;

返回将要移除的Supplementary View对应的索引组成的数组。如果你不想移除任何给定的类型的Supplementary View,请返回空数组。
无论你删除Collection View中cell还是sectionCollection View都会调用这个方法。实现这个方法让你的布局对象有机会删除不再需要的Supplementary View
Collection View在调用- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;- (void)finalizeCollectionViewUpdates;方法之间调用这个方法。

- (NSArray<NSIndexPath *> *)indexPathsToDeleteForDecorationViewOfKind:(NSString *)elementKind;

返回将要移除的Decoration View对应的索引组成的数组。如果你不想移除任何给定的类型的Decoration View,请返回空数组。
无论你删除Collection View中cell还是sectionCollection View都会调用这个方法。实现这个方法让你的布局对象有机会删除不再需要的Decoration View
Collection View在调用- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;- (void)finalizeCollectionViewUpdates;方法之间调用这个方法。

- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;

返回一个Item从Collection View中被移除时的结束布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Item被删除之前都会调用。
Collection View使用这个信息作为动画的结束位置。(动画的起始位置是这个ItemCollection View中的当前位置。)如果你返回nil,那么Item会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil

- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;

返回一个Supplementary View从Collection View中被移除时的结束布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Supplementary View被删除之前都会调用。
Collection View使用这个信息作为动画的结束位置。(动画的起始位置是这个Supplementary ViewCollection View中的当前位置。)如果你返回nil,那么Supplementary View会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil

- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;

返回一个Decoration View从Collection View中被移除时的结束布局信息。
这个方法在- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;方法后调用,在- (void)finalizeCollectionViewUpdates;方法之前调用,在任何一个Decoration View被删除之前都会调用。
Collection View使用这个信息作为动画的结束位置。(动画的起始位置是这个Decoration ViewCollection View中的当前位置。)如果你返回nil,那么Decoration View会使用它最后的属性作为动画的开始和结束位置。
这个方法的默认实现就是返回nil

- (NSIndexPath *)targetIndexPathForInteractivelyMovingItem:(NSIndexPath *)previousIndexPath withPosition:(CGPoint)position;

返回在Collection View的边界上指定位置的Item的索引值。
在一个Item的交互过程中,这个方法映射了一些在Collection View的边界上的点对应的索引值。这个方法的默认实现是搜索给定位置存在的cell并返回这个cell的索引值。如果有多个cell在同一个位置,这个方法返回最顶端的cell——即,布局属性zIndex属性值最大的cell
如果需要更改索引值的确定方式,你可以重写这个方法。例如,你可能会返回最小的zIndex属性值的cell的索引值。如果你重写了这个方法,你不需要调用super

4. 无效化布局

- (void)invalidateLayout;

使当前布局无效,并触发一个布局更新。
你可以在任何时间调用这个方法来更新布局信息。这个方法会使Collection View自己的布局无效,并且立刻返回。因此,你可以在同一个block中多次调用这个方法而不多次触发布局更新。实际上的布局更新发生在下一个视图布局更新周期中。
如果你重写这个方法,你必须在你的实现中的某个点调用super

- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context;
  • context UICollectionViewLayoutInvalidationContext - 标示出了无效化哪一部分的布局。

使用提供的上下文对象无效化当前的布局。
这个方法的默认实现是使用UICollectionViewLayoutInvalidationContext类的基本属性来优化布局过程。如果你给你的布局定义了一个自定义的上下文对象,重写这个方法,并将这个上下文对象的任何自定义属性用于你的布局的计算。
如果你重写这个方法,你必须在你的实现中的某个点调用super

@property(class, nonatomic, readonly) Class invalidationContextClass;

返回用于创建布局无效上下文的类。
如果你子类化UICollectionViewLayout,并且使用一个自定义的无效上下文对象来提高你的布局更新的性能,重写这个方法并返回你的UICollectionViewLayoutInvalidationContext子类。当Collection View需要无效化你的布局,它会使用你提供的这个类创建一个合适的无效上下文对象。

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

告诉布局对象新的Collection Viewbounds是否需要布局更新。返回YES表示Collection View需要布局更新,返回NO表示布局不需要更改。
这个方法的默认实现是返回NO。子类可以重写这个方法,并根据Collection Viewbounds中是否要求改变cellSupplementary View的布局来返回一个适当的值。如果Collection Viewbounds改变并且这个方法返回了YESCollection View就会调用- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context;方法无效化布局。

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds;

bounds发生改变时返回一个需要变化的定义了部分布局的上下文对象。这个方法不可以返回nil
这个方法的默认实现是创建一个invalidationContextClass提供的类的实例并且返回这个实例。如果你想要使用对你的布局自定义的无效上下文对象,需要重写这个方法返回你的自定义类的实例。
如果你想要在响应bounds改变时创建并配置你的自定义无效上下文你可以重写这个方法。如果你重写了这个方法,你必须首先调用super来得到返回的无效上下文对象。得到这个对象之后,设置你想要设置的属性,然后返回这个对象。

- (BOOL)shouldInvalidateLayoutForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes;
  • preferredAttributes UICollectionViewLayoutAttributes - cell- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes;方法返回的布局属性
  • originalAttributes UICollectionViewLayoutAttributes - 布局对象对cell的最初建议属性

一个自动调整大小的cell改变时,询问布局对象是否需要一个较大的更新。当一个Collection View包含自动调整大小的Cell时,让这些Cell在自己的布局属性生效之前有机会修改这些属性。一个自动调整大小的Cell可能指定一个不同的Cell大小而不是提供的布局对象。当这个Cell提供一个不同的属性集合,Collection View调用这个方法来确定Cell的改变是否需要较大的布局更新。
如果你实现一个自定义布局,你可以重写这个方法并且用这个方法根据给定的属性来确定是否你的布局需要被无效化。这个方法的默认实现是返回NO

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes;

当一个动态Cell改变时,返回一个上下文对象来标示出需要改变的部分布局
这个方法的默认实现是创建一个invalidationContextClass提供的类的实例,并返回这个实例。如果你想要对你的布局使用一个自定义无效上下文对象,重写这个方法,并返回你的自定义的类的实例。
子类化可以重写这个方法,使用这个方法在返回之前来执行额外的对无效上下文的配置。在你的自定义实现中调用super,以便父类可以执行对这个对象的基本配置。

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForInteractivelyMovingItems:(NSArray<NSIndexPath *> *)targetIndexPaths withTargetPosition:(CGPoint)targetPosition previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths previousPosition:(CGPoint)previousPosition;
  • targetIndexPaths NSArray - 正在移动的Item的当前索引值。
  • targetPosition CGPoint - Collection View坐标系内的点,是Item可能拖动的点。
  • previousIndexPaths NSArray - 正在移动的Item的之前的索引值。
  • previousPosition CGPoint - Collection View坐标系内的点。这个点是之前用来确定Item拖动点的。

返回一个上下文对象,这个对象标示了在布局中被交互移动的Item
在交互移动一个或多个Item的过程中,布局对象使用这个方法来获取无效上下文。这个方法的默认实现是创建一个invalidationContextClass提供的类的对象,使用提供的信息填入这个对象,并且返回这个对象。如果你想要对你的布局使用一个自定义无效上下文对象,重写这个方法,并返回你的自定义的类的实例。
子类化可以重写这个方法,使用这个方法在返回之前来执行额外的对无效上下文的配置。在你的自定义实现中调用super,以便父类可以执行对这个对象的基本配置。

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:(NSArray<NSIndexPath *> *)indexPaths previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths movementCancelled:(BOOL)movementCancelled;
  • indexPaths NSArray - Item的最终索引值。对于取消的交互,这个索引值对应了Item的最初索引值。
  • previousIndexPaths NSArray - Item之前的索引值。这个参数包含了Collection View在一系列移动中报告的最后一组索引值。
  • movementCancelled BOOL - 标示了移动交互是成功结束还是被取消了。

返回一个上下文对象,这个对象标示了被移动的Item
当交互移动一个或多个Item结束时(移动成功或者被用户取消了移动),布局对象使用这个方法来获取无效上下文。这个方法的默认实现是创建一个invalidationContextClass提供的类的对象,使用提供的信息填入这个对象,并且返回这个对象。如果你想要对你的布局使用一个自定义无效上下文对象,重写这个方法,并返回你的自定义的类的实例。
子类化可以重写这个方法,使用这个方法在返回之前来执行额外的对无效上下文的配置。在你的自定义实现中调用super,以便父类可以执行对这个对象的基本配置。

5. Coordinating Animated Changes

- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds;

为了动态改变视图的bounds或者Item的插入删除准备布局对象。
Collection View在执行任何动态改变视图的bounds或者动态的插入删除Item之前都会调用这个方法。这个方法让布局对象有机会为这些动态改变进行任何需要的计算准备。具体来说,你可能使用这个方法计算插入或删除的Item的最初的和最终的位置,以便当需要这些值的时候你可以返回这些值。
你也可以使用这个方法来处理额外的动画。你创建的任何动画被添加到动画的block中,用来处理插入、删除以及bounds的改变。

- (void)finalizeAnimatedBoundsChange;

在动态改变视图bounds或者Item的插入删除之后进行清理。
Collection View在创建改变视图bounds的动画或者动态插入或删除Item之后调用这个方法。这个方法让布局对象有机会清除和这些操作有关的内容。
你也可以使用这个方法来处理额外的动画。你创建的任何动画被添加到动画的block中,用来处理插入、删除以及bounds的改变。

6. 两个布局之间的过渡

- (void)prepareForTransitionFromLayout:(UICollectionViewLayout *)oldLayout;

告诉布局对象准备为Collection View安装布局。
在执行布局转换之前,Collection View调用这个方法,以便与你的布局对象可以执行一些最初的有需要的计算来生成布局属性

- (void)prepareForTransitionToLayout:(UICollectionViewLayout *)newLayout;

告诉布局对象,这个正要从Collection View中被移除的布局。
在执行布局转换之前,Collection View调用这个方法,以便与你的布局对象可以执行一些最初的有需要的计算来生成布局属性

- (void)finalizeLayoutTransition;

告诉布局对象在过渡动画发生之前执行任何最终步骤。
Collection View已经了解了从一个布局转换到另一个布局所有需要的布局属性后,Collection View调用这个方法。你可以使用这个方法清除任何数据结构或者清除你在prepareForTransitionFromLayoutprepareForTransitionToLayout方法中实现时产生的缓存。

7. 注册Decoration View

- (void)registerClass:(Class)viewClass forDecorationViewOfKind:(NSString *)elementKind;
  • viewClass Class - 用来创建Decoration View的类。
  • elementKind NSString - Decoration View的类型。你可以使用这个字符串在布局中来区分不同的Decoration View。这个参数不可以传nil,也不可以传入一个空的字符串。

注册一个Collection View用来创建Decoration View的类。
这个方法让布局对象有机会注册一个在Collection View中使用的Decoration ViewDecoration View为整个Collection View提供可见的装饰,但是和Collection View的数据源提供的数据没有关系。
你不需要显式的创建Decoration View。注册一个之后,布局对象来决定是否需要一个Decoration View,如果需要则通过layoutAttributesForElementsInRect:方法返回对应的布局属性。对于给定的Decoration View布局属性Collection View会根据注册的信息来创建(或者重用)一个视图并且自动展示它。
如果你之前使用同样的字符串注册一个类或者nib文件,你在viewClass参数中指定的这个类会替换旧的记录。如果你想取消注册Decoration View,你可以对viewClass指定为nil

- (void)registerNib:(UINib *)nib forDecorationViewOfKind:(NSString *)elementKind;

注册一个Collection View用来创建Decoration Viewnib文件。
这个方法让布局对象有机会注册一个在Collection View中使用的Decoration ViewDecoration View为整个Collection View提供可见的装饰,但是和Collection View的数据源提供的数据没有关系。
你不需要显式的创建Decoration View。注册一个之后,布局对象来决定是否需要一个Decoration View,如果需要则通过layoutAttributesForElementsInRect:方法返回对应的布局属性。对于给定的Decoration View布局属性Collection View会根据注册的信息来创建(或者重用)一个视图并且自动展示它。
如果你之前使用同样的字符串注册一个类或者nib文件,你在viewClass参数中指定的这个类会替换旧的记录。如果你想取消注册Decoration View,你可以对viewClass指定为nil

8. 初始化

- (instancetype)init;
- (instancetype)initWithCoder:(NSCoder *)aDecoder;

推荐阅读更多精彩内容