UICollectionViewLayout 的基础知识

布局对象(UICollectionViewLayout)根据 布局的设计定义集合视图中项目的位置大小视觉状态。布局的视图 由 集合视图的数据源创建。

第五章: Crafting Custom Layouts Using UICollectionViewLayout (使用 UICollectionViewLayout 自定义布局)
  • 5.1.Subclassing UICollectionViewLayout (子类化 UICollectionViewLayout)
  • 5.2.Animating UICollectionViewLayout Changes(动画 UICollectionViewLayout 变化)
  • 5.3.Stacking Layouts (堆叠布局)
第六章: Adding Interactivity to UICollectionView (向 UICollectionView 添加交互性)
  • 6.1. Basic Gesture Recognizer (基本手势识别器)
  • 6.2.Responding to Taps (点击
  • 6.3.Pinch and Pan Support (Pinch缩放 和 Pan平移 支持)
  • 6.4.Layout-to-Layout Transitions (布局到布局 的转换
  • 6.5.UIKit Dynamics (动画库 UIKit Dynamics (即将基于物理的动画应用到视图中)

UIKIt Dynamic各种效果: 1.重力效果 2.碰撞效果 3.碰撞效果 4.弹跳效果 5.瞬间移位 6.推力效果 7.元素属性 具体详见:UIKit Dynamics

那当集合视图向用户显示内容时,实际发生的事件顺序是什么?
  • 首先,集合视图询问其数据源(data source)以获取有关要显示给用户的内容的信息。这包括 每个单独section 的 number of sections 和 the number of items 以及 supplementary views。

  • 接下来,集合视图从其布局对象(layout object)中收集有关如何显示 单元格(cells)、补充视图(Supplementary Views)和装饰视图(Decoration Views)的信息。而此信息存储在名为 UICollectionViewLayoutAttributes 的类的实例中。

  • 最后,集合视图将布局信息(UICollectionViewLayoutAttributes)转发给单元格(cells)、补充视图(Supplementary Views)和装饰视图(Decoration Views)。然后每一个类把接受到的布局信息layout attributes 应用到自身。

只要现有布局无效,就会发生这些步骤,您可以通过在布局对象(UICollectionViewLayout)上调用 invalidateLayout 来强制执行这些步骤。

类似地,每次将项目插入到集合视图或从集合视图中删除时,都会为正在添加或删除的项目执行额外的布局过程。但是,集合视图始终将布局限制为在屏幕上可见的对象。

通常 在创建集合视图时指定布局对象,但也可以动态更改集合视图的布局。布局对象存储在collectionViewLayout属性中。设置此属性可直接立即更新布局,而无需设置更改动画。

1、如果要设置更改的动画,请调用setCollectionViewLayout:animated:completion:方法。

2、要创建交互式转换(由手势识别器或触摸事件驱动的转换),请使用startInteractiveTransitionToCollectionViewLayout:completion:方法更改布局对象。该方法安装一个 中间布局对象,该对象与您的手势识别器或事件处理代码配合使用,以跟踪转换进度。

3、当事件处理代码确定转换已完成时,它将调用finishInteractiveTransitioncancelInteractiveTransition 方法以删除中间布局对象并安装预期的目标布局对象。

UICollectionViewLayout

  • 一个抽象基类,用于生成集合视图的布局信息。

一、要重写的方法

每个布局对象都应该实现以下方法:

  • 这些方法提供了集合视图在屏幕上放置内容所需的基本布局信息。如果你的布局不支持补充视图或装饰视图,就不要实现相应的方法。
objectivec 复制代码
//子类必须重写此属性,并使用它返回UICollectionView内容的宽度和高度。
//这些值表示所有内容的宽度和高度,而不仅仅是当前可见的内容。
//集合视图使用此信息来配置自己的内容大小,以便于滚动。
// 此方法的默认实现返回CGSizeZero。 
@property(nonatomic, readonly) CGSize collectionViewContentSize;

//子类必须重写此方法,并使用它返回视图与指定矩形相交的所有项的 布局信息。
//您的实现应该返回所有视觉元素的属性,包括单元格、补充视图和装饰视图。
//在创建布局属性时,始终创建表示正确元素类型(单元格、补充或装饰)的属性对象。
//集合视图区分每种类型的属性,并使用这些信息来决定创建哪些视图以及如何管理它们。
//返回的是布局属性对象(UICollectionViewLayoutAttributes)的数组,
//默认实现返回nil。
-(NSArray<UICollectionViewLayoutAttributes *> *)
    layoutAttributesForElementsInRect:(CGRect)rect;

//子类必须重写此方法,并使用它返回集合视图中 item 的布局信息。
//使用此方法仅为具有相应单元格的 item 提供布局信息。
//请不要将这个方法用于 补充视图或装饰视图!!
-(UICollectionViewLayoutAttributes *)
    layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

//如果布局对象定义了任何补充视图,
//则必须重写此方法并使用它返回指定补充视图(Supplementary View)的布局属性。
//elementKind 标识补充视图(Supplementary View)类型的字符串。
//indexPath  视图的索引路径.
- (UICollectionViewLayoutAttributes *)
  layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind
     atIndexPath:(NSIndexPath *)indexPath;

//如果布局对象定义了任何装饰视图,
//则必须重写此方法并使用它来返回指定装饰视图(Decoration View)的布局属性。
//elementKind 标识 装饰视图(Decoration View)类型的字符串。
//indexPath  视图的索引路径.
- (UICollectionViewLayoutAttributes *)
    layoutAttributesForDecorationViewOfKind:(NSString*)elementKind 
      atIndexPath:(NSIndexPath *)indexPath;

//子类可以覆盖它,
//并根据集合视图边界的更改 是否需要 更改单元格和补充视图的布局 来返回适当的值。
//如果集合视图需要更新布局,则为YES;如果布局不需要更改,则为NO。默认实现返回NO。
//如果集合视图的边界发生了变化,并且该方法返回YES,
//则集合视图将通过调用invalidatelayoutithcontext:方法使布局失效。
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

当集合视图中的数据发生变化,要插入删除项目 时,集合视图要求其布局对象 更新 布局信息。特别是,任何 移动添加删除 的 项目 都 必须更新其布局信息,以反映其新位置。对于移动的 项目,集合视图使用标准方法检索项目的更新布局属性。对于插入或删除的项目,集合视图调用一些不同的方法,您应该重写这些方法以提供适当的布局信息:

objectivec 复制代码
#pragma mark ------- 插入-------------
//此方法检索 即将插入 到集合视图中的item的  初始位置和状态 的布局信息。
//集合视图使用此信息作为任何动画的起点。(动画的终点是item在集合视图中的新位置。)
//如果返回nil,布局对象将使用item 的最终属性作为动画的 开始点和结束点。
//此方法的默认实现将返回nil。
//注意:该方法在 prepareForCollectionViewUpdates 方法之后 和
//finalizeCollectionViewUpdates方法 之前 被调用,用于任何 即将插入 的item。
- (UICollectionViewLayoutAttributes *)
  initialLayoutAttributesForAppearingItemAtIndexPath:
         (NSIndexPath *)itemIndexPath;

//此方法检索 即将插入 到集合视图中的 补充视图的 初始位置和状态 的布局信息。
//集合视图将此信息用作任何动画的起点.(动画的终点是补充视图在集合视图中的新位置.)
//如果返回nil,布局对象将使用 补充视图的最终属性 作为动画的 开始点和结束点。
//此方法的默认实现返回nil。
//注意:此方法在prepareForCollectionViewUpdates:方法之后 和  
//finalizeCollectionViewUpdates:方法之前 调用,用于任何 即将插入 的补充视图。
- (UICollectionViewLayoutAttributes *)
initialLayoutAttributesForAppearingSupplementaryElementOfKind:
(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;

//此方法检索 即将插入 到集合视图中的 装饰视图的 初始位置和状态 的布局信息。 
//集合视图使用这些信息作为任何动画的起点.(动画的结束点是视图在集合视图中的新位置.)
//如果返回nil,布局对象使用装饰视图的最终属性 作为动画的 开始点和结束点。
//此方法的默认实现将返回nil。
//注意:该方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于任何 即将插入 的装饰视图。
- (nullable UICollectionViewLayoutAttributes *)
     initialLayoutAttributesForAppearingDecorationElementOfKind:
      (NSString *)elementKind 
         atIndexPath:(NSIndexPath *)decorationIndexPath;

#pragma mark ------- 删除 -------------
//此方法检索 即将从集合视图中 删除的item的 最终位置和状态 的布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是item的当前位置。)
//如果你返回nil,布局对象对item的 动画的开始点和结束点 使用相同的属性。
//此方法的默认实现将返回nil。
//注意:此方法在 prepareForCollectionViewUpdates 方法之后和
//finalizeCollectionViewUpdates方法 之前 被调用,用于任何即将被删除的item。
- (UICollectionViewLayoutAttributes *)
    finalLayoutAttributesForDisappearingItemAtIndexPath:
       (NSIndexPath *)itemIndexPath;

//此方法检索 即将从集合视图中 删除的补充视图的 最终位置和状态 的布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是视图的当前位置。)
//如果你返回nil,布局对象对补充视图的 动画的开始点和结束点使用相同的属性。
//此方法的默认实现将返回nil。
//注意:该方法在 prepareForCollectionViewUpdates 方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于任何即将被删除的补充视图。
- (nullable UICollectionViewLayoutAttributes *)
  finalLayoutAttributesForDisappearingSupplementaryElementOfKind:
 (NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
  
//此方法检索 即将从集合视图中 删除的装饰视图的 最终位置和状态的 布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是视图的当前位置。)
//如果你返回nil,布局对象对装饰视图的 动画的开始点和结束点使用相同的属性。
//此方法的默认实现将返回nil。 
//注意:该方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于任何即将被删除的装饰视图。
- (nullable UICollectionViewLayoutAttributes *)
finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind 
       atIndexPath:(NSIndexPath *)decorationIndexPath;

除了这些方法之外,您还可以重写 prepareForCollectionViewUpdates: 来处理 任何与布局相关的准备工作

您也可以重写 finalizeCollectionViewUpdates: 方法,并使用它将动画添加到整个动画块中,或实现任何与最终布局相关的任务。

objectivec 复制代码
//在集合视图的内容即将更改(插入或删除项目)时会通知其布局对象,以便根据需要调整布局。
//这个过程的第一步是调用这个方法,让布局对象知道 预期会发生什么变化。之后,
//将进行其他调用,以收集将在集合视图周围设置动画的插入、删除和移动项目的布局信息。
//updateItems 标识正在进行的更改的 UICollectionViewUpdateItem 对象数组。
- (void)prepareForCollectionViewUpdates:
    (NSArray<UICollectionViewUpdateItem *> *)updateItems;

//执行集合视图 更新期间所需的 任何附加动画 或 清理。 
//集合视图调用此方法,作为继续设置任何更改的动画之前的最后一步。
//此方法在用于执行所有 插入、删除 和 移动动画的 动画块中调用,
//因此可以根据需要使用此方法 创建其他动画。除此以外,
//您可以使用此方法来执行与管理 布局对象的状态信息相关联的 任何最后一分钟任务。
- (void)finalizeCollectionViewUpdates;
二、使用失效上下文优化布局性能

在设计自定义布局时,您可以通过仅使布局中 实际更改的部分无效 来提高性能。当您更改项时,调用invalidateLayout方法将强制集合视图重新计算所有布局信息重新应用它。 更好的解决方案是只重新计算更改的布局信息,这正是无效上下文允许您做的事情。无效上下文允许您指定布局的哪些部分被更改。然后,布局对象可以使用该信息来最小化它重新计算的数据量

当您 更改 布局或数据源对象插入或删除项以及调用reloadData方法时,它会创建一个无效上下文。若要为布局定义自定义无效上下文,要创建UICollectionViewLayoutInvalidationContext的子类。在子类中,定义 表示布局数据中可以 独立重新计算的 部分的自定义属性。当需要在运行时使布局无效时,那需要创建无效上下文子类的实例,根据更改的布局信息配置自定义属性,并将 该对象传递给布局的invalidateLayoutWithContext:方法。该方法的自定义实现可以使用无效上下文中的信息仅重新计算布局中已更改的部分

如果为布局对象( UICollectionViewLayout )定义自定义无效上下文类,则还应重写invalidationContextClass方法并返回自定义类。集合视图总是在需要无效上下文时创建指定类的实例。从该方法返回自定义子类可以确保 布局对象始终具有所需的无效上下文

2.1、使集合视图数据无效
objectivec 复制代码
//您不能自己设置此属性。集合视图会根据特定类型的布局无效场景 设置它。
//例如,当您更改当前布局对象、更改集合视图的数据源或调用reloadData方法
//并随后请求布局无效上下文时,集合视图将其设置为YES。
//如果此属性设置为YES,则布局对象 应重新计算 其所有 与布局相关的数据。
@property (nonatomic, readonly) BOOL invalidateEverything; 

//您不能自己设置此属性。集合视图会根据特定类型的布局无效场景 设置它。
//例如,当您插入或删除项或调用集合视图的reloadData方法时,集合视图将其设置为YES。
//如果此属性设置为YES,布局对象应该查询它的委托 以获得部分和项的数量,
//并根据新的项的数量更新其布局。
@property (nonatomic, readonly) BOOL invalidateDataSourceCounts; 
2.2、使内容区域无效
objectivec 复制代码
//使用此属性可以更改集合视图的内容偏移量。
//更改该值会导致 集合视图 将指定的x和y值 添加到其contenttoffset属性中。
//因此,正值增加内容偏移量,负值减少内容偏移量。此属性的默认值是CGPointZero。
@property (nonatomic) CGPoint contentOffsetAdjustment; 

//使用此属性可更改集合视图内容区域的大小。
//更改该值会导致集合视图 将指定的高度和宽度值 添加到其contentSize属性中。
//因此,正值会扩大内容区域,负值会缩小内容区域。该属性的默认值是CGSizeZero。
@property (nonatomic) CGSize contentSizeAdjustment; 
2.3、使特定项目无效
objectivec 复制代码
//表示指定的已失效单元格的索引路径数组。数组包含零个或多个NSIndexPath对象,
//每个NSIndexPath对象,表示一个失效单元格的索引值
@property (nonatomic, readonly, nullable)
      NSArray<NSIndexPath *> *invalidatedItemIndexPaths;
      
//调用此方法 可通过indexPaths索引数组知道有哪些失效的单元格需要更新布局。 
-(void)invalidateItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

//指定的已失效的补充视图的字典,这个字典中的键是无效补充视图的elementkind类型字符串。
//每个键的值是一个NSIndexPath对象数组,数组包含零个或多个NSIndexPath对象,
//每个NSIndexPath对象,表示一个失效补充视图的索引值。
@property (nonatomic, readonly, nullable) 
       NSDictionary<NSString *, NSArray<NSIndexPath *> *> 
               *invalidatedSupplementaryIndexPaths; 
               
//调用此方法 可通过elementKind类型字符串得到的失效补充视图的索引数组,
//从而知道有哪些失效的补充视图需要更新布局。
//如果使用相同的elementKind参数值 调用此方法两次或多次,
//则该方法会将新的索引路径与先前指定的索引路径合并。
- (void)invalidateSupplementaryElementsOfKind:(NSString *)elementKind 
      atIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
              
//表示指定的已失效的装饰视图的字典。这个字典中的键是装饰视图的elementkind类型字符串。
//每个键的值是一个NSIndexPath对象数组,数组包含零个或多个NSIndexPath对象,
//每个NSIndexPath对象,表示一个失效补充视图的索引值。
@property (nonatomic, readonly, nullable) 
       NSDictionary<NSString *, NSArray<NSIndexPath *> *> 
              *invalidatedDecorationIndexPaths; 
              
//调用此方法 可通过elementKind类型字符串得到的装饰视图的索引数组,
//从而知道有哪些失效的装饰视图需要更新布局。
//如果使用相同的elementKind参数值调用此方法两次或多次,
//则该方法将新的索引路径与先前指定的索引路径合并。
- (void)invalidateDecorationElementsOfKind:(NSString *)elementKind 
     atIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
2.4、使项目顺序无效
objectivec 复制代码
//此属性表示集合视图中正在进行或者刚刚结束移动的items的上一个位置的索引路径数组。
//将此属性与targetIndexPathsForInteractivelyMovingItems属性一起使用,
//以确定需要对哪些受影响的项进行哪些更改。对于大多数其他更新,此属性的值为nil。
@property (nonatomic, readonly, copy, nullable) 
       NSArray<NSIndexPath *> 
              *previousIndexPathsForInteractivelyMovingItems; 

//此属性表示集合视图中正在进行或者刚刚结束移动的items的新位置的索引路径数组。
//将此属性与previousIndexPathsForInteractivelyMovingItems属性一起使用,
//以确定需要对哪些受影响的项进行哪些更改。对于大多数其他更新,此属性的值为nil。
@property (nonatomic, readonly, copy, nullable) 
  NSArray<NSIndexPath *> 
         *targetIndexPathsForInteractivelyMovingItems; 
         
//用于确定移动项目位置的当前点。该值表示用于确定
//targetIndexPathsForInteractivelyMovingItems属性中的新索引路径的点。
//您可以根据需要使用这个点来计算项目在布局中的位置。
@property (nonatomic, readonly) CGPoint interactiveMovementTarget;
三、UICollectionViewLayout (布局对象) 其他方法:
3.1、创建集合视图布局的方法:
objectivec 复制代码
typedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) {
    UICollectionViewScrollDirectionVertical,
    UICollectionViewScrollDirectionHorizontal
};
//创建集合视图布局对象。
- (instancetype)init;
//从给定unarchiver中的数据创建集合视图布局对象。
- (instancetype)initWithCoder:(NSCoder *)coder;
3.2、获取集合视图信息的方法:
objectivec 复制代码
// 当前使用此布局对象的集合视图对象。 
@property(nullable, nonatomic, readonly) UICollectionView *collectionView;
// 集合视图内容的宽度和高度。 
@property(nonatomic, readonly) CGSize collectionViewContentSize;
3.3、提供布局属性的方法:
objectivec 复制代码
//如果你子类化UICollectionViewLayoutAttributes来管理额外的布局属性,
//你应该重写这个方法并返回你的自定义子类。
//创建布局属性的方法在创建新的布局属性对象时使用这个类。
//此方法仅用于子类,不需要由代码调用。
@property(class, nonatomic, readonly) Class layoutAttributesClass;

//布局更新 发生在集合视图 首次显示其内容时,
//以及由于视图更改而显式或隐式地使布局无效之后,
//在重新查询布局信息之前,集合视图再次调用prepareLayout方法 
//在每次布局更新期间,集合视图都会首先调用此方法,
//使布局对象有机会为即将到来的布局操作做准备。
//此方法的默认实现不执行任何操作。
//子类可以覆盖它,并使用它来 设置数据结构 或执行稍后 执行布局所需的任何初始计算。
//如果子类重写,它们应该始终调用super。
- (void)prepareLayout;

//子类必须重写此方法,并使用它返回视图与指定矩形相交的所有项的布局信息。
//您的实现应该返回所有视觉元素的属性,包括单元格、补充视图和装饰视图。
//创建布局属性时,始终创建表示正确元素类型(单元格、补充或装饰)的属性对象。
//集合视图区分每种类型的属性,并使用这些信息来决定创建哪些视图以及如何管理它们。
//返回的是UICollectionViewLayoutAttributes对象的数组,
//表示单元格和视图的布局信息。默认实现返回nil。
- (NSArray<__kindof UICollectionViewLayoutAttributes *> *)
          layoutAttributesForElementsInRect:(CGRect)rect;

//子类必须重写此方法,并使用它返回集合视图中 item 的布局信息。
//使用此方法仅为具有相应单元格的 item 提供布局信息。
//请不要将这个方法用于 补充视图或装饰视图!   
- (UICollectionViewLayoutAttributes *)
     layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

//当item由于用户交互而移动时,布局对象使用此方法检索项在指定位置时要使用的布局属性。
//此方法的默认实现返回一个item现有属性的副本,并进行了两个更改:
//中心点被设置为position中的值,zIndex值被设置为NSIntegerMax,
//以便该item在集合视图中浮动在其他item之上。
//子类可以覆盖这个方法,并根据需要修改额外的布局属性。
//如果重写此方法,请首先调用super检索该项的现有属性,然后对返回的结构进行更改。
//indexPath 被移动的项目的索引路径。
//position   item 在集合视图坐标系中的当前位置
- (UICollectionViewLayoutAttributes *)
     layoutAttributesForInteractivelyMovingItemAtIndexPath:                   
         (NSIndexPath *)indexPath  
           withTargetPosition:(CGPoint)position;

//如果布局对象定义了任何补充视图,
//则必须重写此方法,并使用它返回这些补充视图的布局信息。
//elementKind 标识补充视图类型的字符串。
//indexPath  视图的索引路径.
- (UICollectionViewLayoutAttributes *)
 layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind
     atIndexPath:(NSIndexPath *)indexPath;
 
//如果布局对象定义了任何装饰视图,
//则必须重写此方法并使用它来返回这些装饰视图的布局信息。
//elementKind 标识 装饰视图(Decoration View)类型的字符串。
//indexPath  视图的索引路径.
- (UICollectionViewLayoutAttributes *)
   layoutAttributesForDecorationViewOfKind:(NSString*)elementKind 
      atIndexPath:(NSIndexPath *)indexPath;

//在布局 更新期间,或在布局之间转换时,集合视图调用此方法,
//以便您有机会 在动画结束时 更改成您想要使用的内容偏移量。
//此方法默认返回proposedContentOffset参数中的值为内容偏移量。
//proposedContentOffset:可见区域的调整后的左上角。
//如果动画或过渡可能导致items的定位方式不适合自己的设计,则可以重写此方法。
//注意:
//集合视图在调用prepareLayout和collectionViewContentSize方法之后调用该方法!
-(CGPoint)targetContentOffsetForProposedContentOffset:
      (CGPoint)proposedContentOffset;

//检索停止滚动的点。 
//如果希望滚动行为捕捉到特定的边界,可以重写此方法并使用它来更改停止的点。例如,
//您可以使用此方法始终在items之间的边界上停止滚动,而不是在items中间停止滚动。
//proposedContentOffset: 建议停止滚动的点(在集合视图的内容视图中)。
//如果不做任何调整,滚动就会自然停止。该点反映了调整后的可见区域的左上角。
//此方法的默认实现,返回proposedContentOffset参数中的值。
//velocity : 当前沿水平轴和垂直轴的滚动速度。该值以每秒点数为单位。
-(CGPoint)targetContentOffsetForProposedContentOffset:
   (CGPoint)proposedContentOffset 
        withScrollingVelocity:(CGPoint)velocity;
3.4、响应集合视图更新的方法:
objectivec 复制代码
#pragma mark -------  响应集合视图更新 
//当 插入或删除items时,集合视图会通知其布局对象,集合视图的内容即将更改,
//以便它可以根据需要调整布局。这个过程的第一步是调用这个方法,
//让布局对象知道预期会发生什么变化。之后,进行其他调用,
//以收集将在集合视图设置动画(插入、删除和移动)的items的布局信息。
- (void)prepareForCollectionViewUpdates:
     (NSArray<UICollectionViewUpdateItem *> *)updateItems;

//执行在集合视图更新期间所需的 任何其他动画或清理。
//集合视图调用此方法作为继续设置任何更改的动画之前的最后一步。
//此方法在用于执行所有插入、删除和移动 动画的 动画块中调用,
//因此可以根据需要使用此方法创建其他动画。
//否则,您可以使用它来执行与管理布局对象的 状态信息相关的 任何最后一分钟的任务。
- (void)finalizeCollectionViewUpdates;

//检索 要添加到布局中的 补充视图的索引路径数组。
//每当向集合视图添加cells或sections时,集合视图都会调用此方法。
//实现此方法使布局对象有机会添加新的补充视图来补充添加的内容。
//集合视图在 调用prepareForCollectionViewUpdates:和 
//finalizeCollectionViewUpdates之间 调用此方法。
//返回的 NSIndexPath对象数组,表示新的补充视图的位置,
//如果不想添加任何补充视图,则为空数组。
- (NSArray<NSIndexPath *> *)
indexPathsToInsertForSupplementaryViewOfKind:(NSString *)elementKind;

//检索表示要添加的 装饰视图的索引路径数组。
//每当向集合视图添加cells或sections时,集合视图都会调用此方法。
//实现此方法使布局对象有机会添加新的装饰视图来补充添加的内容。
//集合视图在调用prepareForCollectionViewUpdates:和
//finalizeCollectionViewUpdates之间 调用此方法。
///返回的 NSIndexPath对象数组,表示新装饰视图的位置,
//如果不想添加任何装饰视图,则为空数组。
- (NSArray<NSIndexPath *> *)
  indexPathsToInsertForDecorationViewOfKind:(NSString *)elementKind;

//检索插入 到集合视图中的 item的 起始布局信息。
//该方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于即将插入的任何项。
//您的实现应该返回描述 该item的 初始位置和状态的布局信息。
//集合视图使用这些信息作为任何动画的起点(动画的结束点是项目在集合视图中的新位置)。
//如果返回的是一个布局属性对象,用于描述要放置相应单元格的位置。
//如果你返回nil,布局对象使用item的final属性作为动画的开始点和结束点。
//此方法的默认实现将返回nil。
- (UICollectionViewLayoutAttributes *)
   initialLayoutAttributesForAppearingItemAtIndexPath:
             (NSIndexPath *)itemIndexPath;

//检索插入到集合视图中的补充视图的起始布局信息。
//该方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于即将插入的任何补充视图。
//您的实现应该返回描述 补充视图 初始位置和状态的布局信息。
//集合视图使用这些信息作为任何动画的起点(动画的结束点是视图在集合视图中的新位置)。
//如果返回的是一个布局属性对象,它描述放置相应补充视图的位置。
//如果你返回nil,布局对象使用item的final属性作为动画的开始点和结束点。
//此方法的默认实现将返回nil。
- (UICollectionViewLayoutAttributes *)
initialLayoutAttributesForAppearingSupplementaryElementOfKind:
     (NSString *)elementKind 
          atIndexPath:(NSIndexPath *)elementIndexPath;

//检索插入到集合视图中的装饰视图的 起始布局信息。
//这个方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于任何即将插入的装饰视图。
//您的实现应该返回描述视图初始位置和状态的布局信息。
//集合视图使用这些信息作为任何动画的起点(动画的结束点是视图在集合视图中的新位置)。
//如果返回的是一个布局属性对象,描述放置相应装饰视图的位置。
//如果你返回nil,布局对象使用item的final属性作为动画的开始点和结束点。
//此方法的默认实现将返回nil。
- (UICollectionViewLayoutAttributes *)
initialLayoutAttributesForAppearingDecorationElementOfKind:
       (NSString *)elementKind 

//检索表示 要删除的补充视图的索引路径数组。
//每当向集合视图删除cells或sections时,集合视图都会调用此方法。
//实现此方法使布局对象有机会删除不再需要的任何补充视图。
//集合视图在调用prepareForCollectionViewUpdates:和
//finalizeCollectionViewUpdates之间调用此方法。
//返回的NSIndexPath对象数组,表示要删除的补充视图;
//如果不想删除任何给定类型的视图,则返回为空数组。
- (NSArray<NSIndexPath *> *)
indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind;

//检索表示要删除的装饰视图的索引路径数组。
//每当向集合视图删除cells或sections时,集合视图都会调用此方法。
//实现此方法使布局对象有机会删除不再需要的任何装饰视图。
//集合视图在调用prepareForCollectionViewUpdates:和
//finalizeCollectionViewUpdates之间调用此方法。
//返回的NSIndexPath对象数组,表示要删除的装饰视图;
//如果不想删除任何给定类型的视图,则返回为空数组。
- (NSArray<NSIndexPath *> *)
  indexPathsToDeleteForDecorationViewOfKind:(NSString *)elementKind;

//检索 即将从集合视图中 删除的item 的最终布局信息。
//该方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于将要删除的任何项。
//您的实现应该返回描述该项的最终位置和状态的布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是物品的当前位置。)
//如果返回的是一个布局属性对象,描述要用作动画删除单元格的终点的单元格的位置。
//如果你返回nil,布局对象对动画的开始点和结束点使用相同的属性。
//此方法的默认实现将返回nil。
- (UICollectionViewLayoutAttributes *)
     finalLayoutAttributesForDisappearingItemAtIndexPath:
           (NSIndexPath *)itemIndexPath;

//检索 即将从集合视图中 删除的补充视图的最终布局信息。
//这个方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于将要删除的任何补充视图。
//您的实现应该返回描述视图的最终位置和状态的布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是视图的当前位置。)
//如果返回的是一个布局属性对象,用于描述补充视图的位置,以作为动画删除的结束点。
//如果你返回nil,布局对象对动画的开始点和结束点使用相同的属性。
//此方法的默认实现将返回nil。
- (nullable UICollectionViewLayoutAttributes *)
   finalLayoutAttributesForDisappearingSupplementaryElementOfKind:
       (NSString *)elementKind
           atIndexPath:(NSIndexPath *)elementIndexPath;

//检索即将从集合视图中移除的装饰视图的最终布局信息。
//这个方法在prepareForCollectionViewUpdates方法之后和
//finalizeCollectionViewUpdates方法之前被调用,用于任何即将被删除的装饰视图。
//您的实现应该返回描述视图的最终位置和状态的布局信息。
//集合视图使用此信息作为任何动画的结束点。(动画的起点是视图的当前位置。)
//如果返回的是一个布局属性对象,它描述装饰视图的位置,用于动画化其移除。
//如果你返回nil,布局对象对动画的开始点和结束点使用相同的属性。
//此方法的默认实现将返回nil。 
- (nullable UICollectionViewLayoutAttributes *)
  finalLayoutAttributesForDisappearingDecorationElementOfKind:
         (NSString *)elementKind 
               atIndexPath:(NSIndexPath *)decorationIndexPath;

//返回 在集合视图中指定位置相对应的索引路径。 (重新排序)
//previousIndexPath: item的上一个索引路径。使用此值可以识别item。
//position: 集合视图边界中的目标点。使用此值可以计算item的新索引路径。 
//在项目的交互移动期间,
//此方法将集合视图的 边界矩形中的点 映射到与这些点的位置 对应的索引路径。
//此方法的默认实现 在指定位置 搜索现有单元格,并返回该单元格的索引路径。
//如果在同一位置有多个单元格,则该方法返回最顶层的单元格,
//即zIndex布局属性值最大的单元格。
//您可以根据需要重写此方法,以更改索引路径的确定方式。
//例如,您可以返回zIndex值最低而不是最高的单元格的索引路径。
//如果重写此方法,则不需要调用super。
- (NSIndexPath *)targetIndexPathForInteractivelyMovingItem:
      (NSIndexPath *)previousIndexPath 
             withPosition:(CGPoint)position;
3.5、使布局无效的方法:
objectivec 复制代码
//使当前布局失效 并触发布局更新。
//你可以在 任何时候调用这个方法 来更新布局信息。
//此方法使集合视图本身的布局无效,并立即返回。
//因此,您可以从同一代码块 多次调用此方法,而不会触发多次布局更新。
//实际的布局更新 发生在下一个视图布局 更新周期。
//如果重写此方法,则必须在实现中的某个时刻调用super。
//调用invalidateLayout方法将强制集合视图重新计算其所有布局信息并重新应用它。
- (void)invalidateLayout;

//使用 所提供的上下文对象中的信息 使当前布局失效。这个方法的默认实现使用
//UICollectionViewLayoutInvalidationContext类的基本属性来优化布局过程。 
//如果您为布局定义了一个自定义上下文对象,请重写此方法,
//并将上下文对象的任何自定义属性应用到布局计算中。
//如果重写此方法,则必须在实现中的某个位置调用super。
- (void)invalidateLayoutWithContext:
     (UICollectionViewLayoutInvalidationContext *)context;
 
//如果将UICollectionViewLayout子类化,
//并使用 自定义无效上下文对象 来 提高布局更新的性能,
//请重写此方法并返回UICollectionViewLayoutInvalidationContext子类。
//当集合视图需要使布局无效时,它会使用您提供的类来创建适当的无效上下文对象。
@property(class, nonatomic, readonly)Class invalidationContextClass;

//子类可以覆盖它,
//并根据集合视图边界的更改 是否需要 更改 单元格和补充视图的布局来返回适当的值。
//如果集合视图的边界发生了变化并且该方法返回YES,
//集合视图将通过调用 invalidatelayoutithcontext: 方法使布局失效。
//如果集合视图需要更新布局,则为YES;如果布局不需要更改,则为NO。
//此方法的默认实现返回NO。
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

//此方法的默认实现:创建一个由invalidationContextClass类方法提供的类的实例,
//并返回该实例。如果你想在你的布局中使用一个自定义的无效上下文对象,
//请始终重写该方法并返回自定义类,不返回nil。
//如果要 创建和配置自定义失效上下文 以响应 边界更改,则可以覆盖此方法。
//如果重写此方法,则必须首先调用super 才能返回无效上下文对象。
//获得此对象后,设置 任何自定义属性 并返回它。
- (UICollectionViewLayoutInvalidationContext *)
    invalidationContextForBoundsChange:(CGRect)newBounds;

//检索上下文对象,该对象标识应根据动态单元格更改 而更改的布局部分。
//无效上下文,其中包含关于需要对布局进行哪些更改的信息。
//此方法的默认实现:创建一个由invalidationContextClass类方法提供的类的实例,
//并返回该实例。如果你想在你的布局中使用一个自定义的无效上下文对象,
//请始终重写该方法并返回自定义类,不返回nil。
//子类可以重写此方法,并在返回 无效上下文之前 使用它来执行额外的配置。
//在自定义实现中,调用super,以便父类可以执行对象的基本配置。
//preferredAttributes:单元格的
//preferredLayoutAttributesFittingAttributes:方法返回的布局属性。
//originalAttributes : 布局对象最初为单元格建议的属性。 
- (UICollectionViewLayoutInvalidationContext *)
   invalidationContextForPreferredLayoutAttributes:
      (UICollectionViewLayoutAttributes *)preferredAttributes 
          withOriginalAttributes
            :(UICollectionViewLayoutAttributes *)originalAttributes;

//询问布局对象对 自定大小单元格的更改 是否需要 布局更新。 
//当集合视图包含 自调整大小的单元格时,
//单元格有机会在应用这些属性之前 修改它们自己的布局属性。
//自定义大小的单元格 可能会指定 与布局对象提供的单元格大小 不同的 单元格大小。
//当单元格提供一组不同的属性时,
//集合视图调用此方法来确定单元格的更改 是否需要更大的布局刷新。
//如果您正在实现自定义布局,
//则可以覆盖此方法并使用它来确定 是否根据指定的属性使布局失效。
//如果该布局应该无效,则为YES;如果不应该无效,则为NO。
//此方法的默认实现返回NO。
- (BOOL)shouldInvalidateLayoutForPreferredLayoutAttributes:
    (UICollectionViewLayoutAttributes *)preferredAttributes
       withOriginalAttributes:
           (UICollectionViewLayoutAttributes *)originalAttributes;


//检索上下文对象,该对象标识在布局中 以交互方式移动的items。
//无效上下文,包括有关需要对布局进行哪些更改的信息。
//当正在进行一个或多个item 的交互式移动时,布局对象使用此方法检索无效上下文。
//默认实现创建invalidationContextClass类方法提供的类的实例,
//用提供的信息填充该实例,并返回该实例。
//如果要在布局中使用自定义无效上下文对象,请始终重写该方法并返回自定义类。
//子类可以重写此方法,并在返回无效上下文之前使用它来执行额外的配置。
//在自定义实现中,调用super,以便父类可以执行对象的基本配置。
//targetIndexPaths(目标索引路径): 正在移动的项的当前位置。
//targetPosition(目标位置) : 集合视图坐标系中的点,它是项目的潜在放置点。
//previousIndexPaths(以前的索引路径): 正在移动的项的先前位置。
//previousPosition( 先前位置 ):  集合视图坐标系中的前一个点。
//这是以前用于确定item 放置点的点。
- (UICollectionViewLayoutInvalidationContext *)
    invalidationContextForInteractivelyMovingItems:
       (NSArray<NSIndexPath *> *)targetIndexPaths 
          withTargetPosition:(CGPoint)targetPosition                               
    previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths                                                                          
    previousPosition:(CGPoint)previousPosition;

//检索上下文对象,该对象标识已移动的 item 
//无效上下文,包括有关需要对布局进行哪些更改的信息。
//当一个或多个item 的交互式移动结束时,布局对象使用此方法检索无效上下文,
//不管移动成功,还是被用户取消,布局对象使用此方法检索无效上下文。
//默认实现:创建invalidationContextClass类方法提供的类的实例,
//用提供的信息填充该实例,然后返回该实例。
//如果要在布局中使用自定义无效上下文对象,请始终重写该方法并返回自定义类。
//子类可以重写此方法,并在返回无效上下文之前使用它来执行额外的配置。
//在自定义实现中,调用super,以便父类可以执行对象的基本配置。
-(UICollectionViewLayoutInvalidationContext *)
invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:ß
      (NSArray<NSIndexPath *> *)indexPaths                                                                                                   
    previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths 
         movementCancelled:(BOOL)movementCancelled;
3.6、协调动画变化的方法:
objectivec 复制代码
//为视图边界的动画更改 或 item的插入或删除 准备布局对象。
//集合视图在 对视图的边界执行任何动画更改之前,或者在动画插入或删除之前 调用此方法。
//该方法为布局对象提供了机会,可以执行 为这些动画更改 做准备 所需的任何计算。
//具体来说,可以使用此方法 计算 插入或删除item的初始或最终位置,
//以便在请求时返回这些值。也可以使用此方法执行其他动画。
//所创建的任何动画都将添加到 用于处理插入、删除和边界更改的动画块中。
//oldBounds :集合视图的当前边界。 
- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds;

//在 对视图的边界进行任何动画更改之后 或在插入或删除item之后 清理。
//集合视图在 创建用于更改视图边界的动画之后,或者在动画插入或删除item之后 调用此方法。
//该方法是布局对象执行 与这些操作相关的任何清理的机会。
//也可以使用此方法来执行其他动画。
//所创建的任何动画都将添加到用于处理插入、删除和边界更改的动画块中。
- (void)finalizeAnimatedBoundsChange;
3.7、布局之间转换的方法:
objectivec 复制代码
//集合视图准备从oldLayout开始转换
//在执行 布局转换之前,集合视图调用此方法,
//以便布局对象可以执行 生成布局属性 所需的任何初始计算。
//oldLayout:准备开始转换之前在集合视图中的布局对象。可以使用此对象根据起始布局对象提供不同的结束属性。
- (void)prepareForTransitionFromLayout:
         (UICollectionViewLayout *)oldLayout;

//集合视图准备转换到这个布局newLayout
//在执行 布局转换之前,集合视图调用此方法,
//以便布局对象可以执行 生成布局属性 所需的任何初始计算。
//newLayout:准备在转换结束后,会被设置为集合视图中新的布局对象。可以使用此对象根据起始布局对象提供不同的结束属性。
- (void)prepareForTransitionToLayout:(UICollectionViewLayout *)newLayout;

//告诉布局对象在 转换动画发生之前 执行任何最后步骤。
//集合视图在收集了执行从 一个布局 转换 到 另一个布局 所需的所有布局属性后 调用此方法。
//你可以使用这个方法来清理你的prepareForTransitionFromLayout:
//或prepareForTransitionToLayout:方法的实现所创建的任何数据结构或缓存。
- (void)finalizeLayoutTransition;
3.8、注册装饰视图的方法:
objectivec 复制代码
//下面2个方法都是使布局对象有机会注册一个装饰视图,以便在集合视图中使用。
//装饰视图为部分或整个集合视图提供视觉装饰,但不绑定到集合视图数据源提供的数据!!
//2个方法都是不需要显式地创建装饰视图。注册一个后,就由布局对象来决定何时需要装饰视图,
//并从其layoutAttributesForElementsInRect:方法中返回相应的布局属性。
//对于指定装饰视图的布局属性,集合视图创建(或重用)视图,并根据注册的信息自动显示它。

//如果您之前注册了具有相同类型字符串的类或nib文件,
//则在viewClass参数中指定的类将替换旧的条目。
//如果你想取消装饰视图的注册,你可以为viewClass指定nil。
- (void)registerClass:(Class)viewClass 
forDecorationViewOfKind:(NSString *)elementKind;

//如果您之前注册了具有相同类型字符串的类或nib文件,
//则在viewClass参数中指定的类将替换旧的条目。
//如果你想取消装饰视图的注册,你可以为viewClass指定nil。
- (void)registerNib:(UINib *)nib 
forDecorationViewOfKind:(NSString *)elementKind;
3.9、支持从右向左布局的方法:
objectivec 复制代码
//用户界面布局方向
//默认实现返回主开发区域的布局方向;FlowLayout返回leftToRight。
//子类可以覆盖此项,以指定布局的实现时间布局方向。  
@property(nonatomic, readonly) UIUserInterfaceLayoutDirection developmentLayoutDirection;

//一个布尔值,指示是否在适当的时间自动翻转水平坐标系统。
//开发过程中使用的语言自然会影响您在配置布局对象时所做的决策。
//当您使用从左到右的语言进行开发时,您的布局信息将自动匹配集合视图的自然坐标系。然而,
//当用户的语言具有从右到左的方向时,您提供的布局信息仍然基于集合视图的自然坐标系。
//对于使用相反方向的语言,这种差异可能会导致布局问题。
//当此属性设置为YES时,集合视图自动翻转其水平坐标系的方向,以匹配当前语言的前沿。
//(developlayoutdirection属性指定用于设计布局的布局方向。)
//翻转水平坐标系可以有效地翻转现有的布局信息,这应该会产生更好看的布局。
//该属性的默认值为NO。
@property(nonatomic, readonly) BOOL flipsHorizontallyInOppositeLayoutDirection;

UICollectionViewTransitionLayout :一种特殊类型的布局对象,它允许您在集合视图中从一种布局更改为另一种布局时实现行为。iOS 13 中 Apple 为 UICollectionView 推出了组合布局 UICollectionViewCompositionalLayout

四、UICollectionViewLayoutAttributes (布局信息属性)

UICollectionViewLayoutAttributes 用于管理集合视图中给定项的布局相关属性。使用其布局信息在其边界内 定位单元格和辅助视图。

在大多数情况下,按原样使用这个类。如果您想用自定义布局属性来补充基本布局属性,您可以子类化并定义任何您想要存储额外布局数据的属性。因为布局属性对象可能会被集合视图复制,所以要确保你的子类遵循NSCopying协议,实现任何合适的方法来将你的自定义属性复制到子类的新实例中。除了定义你的子类,你的UICollectionReusableView对象需要实现applyLayoutAttributes:方法,这样他们就可以在布局时应用任何自定义属性

如果您子类化并实现任何自定义布局属性,您还必须重写继承的isEqual:方法来比较属性的值。在ios7及更高版本中,如果这些属性没有改变,集合视图不会应用布局属性它通过使用isEqual:方法 比较新旧属性对象来确定属性是否发生了变化。由于此方法的默认实现只检查该类的现有属性,因此必须实现自己的方法版本来比较任何附加属性。如果您的自定义属性都相等,则在实现结束时调用super并返回结果值。

4.1、创建布局属性:
objectivec 复制代码
//创建并返回一个表示具有指定索引路径的单元格的布局属性对象。
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;

//创建并返回表示指定补充视图的布局属性对象。 
//与单元格一样,补充视图表示由集合视图的数据源管理的数据。
//但与单元格不同的是,补充视图通常是为特殊目的而设计的。例如,
//页眉和页脚视图的布局与单元格不同,可以为单个部分提供,也可以为整个集合视图提供。
//由您决定如何使用indexPath参数来标识给定的补充视图。
//通常,使用elementKind参数来标识补充视图的类型,
//使用indexPath信息来区分该视图的不同实例。
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind 
    withIndexPath:(NSIndexPath *)indexPath;

//创建并返回表示指定装饰视图的布局属性对象。 
//装饰视图是一种补充视图,主要为一个部分或整个集合视图提供视觉装饰。
//装饰视图是是由布局对象 UICollectionViewLayout 管理数据的。
//不由集合视图数据源管理数据。
//由您决定如何使用indexPath参数来标识给定的装饰视图。
//通常,使用decorationViewKind参数来标识装饰视图的类型,
//使用indexPath信息来区分该视图的不同实例。
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;
4.2、识别被引用的项目
objectivec 复制代码
//集合视图中项的索引路径。 
@property (nonatomic, strong) NSIndexPath *indexPath;
//representedElementCategory:项目的类型。
//可以使用此属性中的值来区分布局属性是用于单元格、补充视图还是装饰视图。
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
//representedElementKind:目标视图的特定布局标识符。
//您可以使用此属性中的值来标识与属性关联的补充视图或装饰视图的特定用途。
//当代表的delementcategory是UICollectionElementCategoryCell时,该值为nil。
@property (nonatomic, readonly, nullable) NSString *representedElementKind; 
4.3、访问布局属性
objectivec 复制代码
@property (nonatomic) CGRect frame;//项的frame
@property (nonatomic) CGRect bounds;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGSize size;
//transform3D的值:使用指定的3D变换的仿射形式替换transform属性中的值
@property (nonatomic) CATransform3D transform3D;
//transform的值:指定的仿射转换的3D变换的仿射形式替换transform3D属性中的值。
@property (nonatomic) CGAffineTransform transform;
@property (nonatomic) CGFloat alpha;
// 指定项目在z轴上的位置。 此属性的默认值为0。
//此属性用于确定布局期间项目的前后顺序。索引值较高的项目显示在值较低的项目的顶部。
//具有相同值的项目具有未确定的顺序。
@property (nonatomic) NSInteger zIndex; 
//作为优化,UICollectionView可能不会为隐藏属性为YES的项创建视图
@property (nonatomic, getter=isHidden) BOOL hidden; 

五、UICollectionViewUpdateItem

UICollectionViewUpdateItem: 描述对集合视图中的项进行的单个更改的对象。

您不能直接创建此类的实例。当更新其内容时,集合视图对象会创建它们,并将它们传递给布局对象的 prepareForCollectionViewUpdates: 方法,该方法可以使用它们来为即将到来的改变准备布局对象。

objectivec 复制代码
typedef NS_ENUM(NSInteger, UICollectionUpdateAction) {
    UICollectionUpdateActionInsert,
    UICollectionUpdateActionDelete,
    UICollectionUpdateActionReload,
    UICollectionUpdateActionMove,
    UICollectionUpdateActionNone
};
//更新之前 项的索引路径。
//nil用于UICollectionUpdateActionInsert
@property (nonatomic, readonly, nullable) NSIndexPath *indexPathBeforeUpdate; 
// 更新之后 项的索引路径。 
//nil用于UICollectionUpdateActionDelete
@property (nonatomic, readonly, nullable) NSIndexPath *indexPathAfterUpdate; 
//正在对项目执行的 操作类型的 常量
@property (nonatomic, readonly) UICollectionUpdateAction updateAction;

六、 UICollectionViewFlowLayout 流布局

UICollectionViewFlowLayout 继承 UICollectionViewLayout

6.1、配置滚动方向

objectivec 复制代码
//这个属性的默认值是UICollectionViewScrollDirectionVertical。
@property(nonatomic) UICollectionViewScrollDirection scrollDirection;
//指定可使用流布局显示的补充视图类型的常量。
NSString *const UICollectionElementKindSectionHeader;
NSString *const UICollectionElementKindSectionFooter;

6.2、配置item间距

objectivec 复制代码
//minimumLineSpacing 最小行距
@property (nonatomic) CGFloat minimumLineSpacing;
//minimumInteritemSpacing:在同一行中 item 之间要使用的最小间距。 
@property (nonatomic) CGFloat minimumInteritemSpacing;

//如果委托未实现collectionView:layout:sizeForItemAtIndexPath:方法,
//则流布局将使用此属性中的值来设置每个单元格的大小。
//这导致所有单元格都具有相同的大小。
//默认大小值为(50.0,50.0)。
@property (nonatomic) CGSize itemSize;

//当单元格动态调整其大小时,提供估算的单元格大小可以提高集合视图的性能。
//估算值让集合视图推迟一些计算,以确定其内容的实际大小。
//不在屏幕上的单元格被假定为估算高度。
//该属性的默认值是CGSizeZero。将其设置为任何其他值,
//如UICollectionViewFlowLayoutAutomaticSize,会导致集合视图使用单元格的
//preferredLayoutAttributesFittingAttributes:方法 查询每个单元格的实际大小。
//如果所有单元格大小相同,则使用itemSize属性而不是此属性来指定单元格大小。
@property (nonatomic) CGSize estimatedItemSize;

//用于自调整单元格大小的占位符大小!!!
//将此常量设置为estimatedItemSize属性的值,
//以便为您的集合视图启用自调整单元格大小。
//这是一个非零的占位符值,它告诉集合视图使用单元格的
//preferredLayoutAttributesFittingAttributes:方法
//查询每个单元格的实际大小。
UIKIT_EXTERN const CGSize UICollectionViewFlowLayoutAutomaticSize;

@property (nonatomic) UICollectionViewFlowLayoutSectionInsetReference sectionInsetReference;//iOS 11.0+;
//sectionInset 页边距 默认为零
//页边距影响页眉视图的初始位置、每行items两侧的最小空间
//以及从最后一行到页脚视图的距离。
//边距的插入不会影响页眉和页脚视图在非滚动方向上的大小。
//如果委托对象未实现collectionView:layout:insetForSectionAtIndex:方法,
//则流布局将使用此属性中的值来设置每个section的边距。
@property (nonatomic) UIEdgeInsets sectionInset;

6.3、配置headers 和 footers

流布局中的每个节都可以有自己的自定义页眉和页脚。若要配置视图的页眉或页脚,请将页眉或页脚的大小配置为非零。实现适当的委托方法或为headerReferenceSize和footerReferenceSize属性分配适当的值。如果页眉或页脚大小为0,则不会将相应的视图添加到集合视图中。

objectivec 复制代码
//如果委托没有实现collectionView:layout:referenceSizeForHeaderInSection:
//方法,则流布局对象使用该属性中设置的默认页眉大小。
//在布局期间,只使用与适当的滚动方向相对应的大小。例如,对于垂直滚动方向,
//布局对象使用方法返回的高度值。(在这种情况下,标题的宽度将被设置为集合视图的宽度。)
//如果适当滚动维度中的大小为0,则不添加标题。
//默认大小值为(0,0)。
@property (nonatomic) CGSize headerReferenceSize;
@property (nonatomic) CGSize footerReferenceSize;

6.4、固定headers 和 footers

objectivec 复制代码
//一个布尔值,指示滚动期间标题是否固定在集合视图边界的顶部。
//当此属性为YES时,section header view将随内容滚动,
//直到它们到达屏幕顶部,此时它们将固定在集合视图的边界的顶部。
//每个滚动到屏幕顶部的新 header view 都会将先前固定的标题视图推到屏幕外。
//该属性的默认值为NO。
@property (nonatomic) BOOL sectionHeadersPinToVisibleBounds;

//一个布尔值,指示滚动期间页脚是否固定在集合视图边界的底部。
//当此属性为YES时,section footer views 将随内容滚动,
//直到它们到达屏幕底部,此时它们将固定在集合视图的边界的底部。
//每个滚动到屏幕底部的footer views 都会将先前固定的页脚视图推到屏幕外。
//该属性的默认值为NO。
@property (nonatomic) BOOL sectionFootersPinToVisibleBounds;
UICollectionViewDelegateFlowLayout

1、获取项目的大小

objectivec 复制代码
//指定项的宽度和高度。两个值都必须大于0。
//如果不实现此方法,流布局将使用itemSize属性中的值来设置项的大小。
//此方法的实现可以返回一组固定的大小,也可以根据单元格的内容动态调整大小。
- (CGSize)collectionView:(UICollectionView *)collectionView
   layout:(UICollectionViewLayout*)collectionViewLayout 
        sizeForItemAtIndexPath:(NSIndexPath *)indexPath;

2、获取分区间距

objectivec 复制代码
//如果不实现此方法,则流布局将使用其sectionInset属性中的值来设置页边距。
//此方法的实现可以返回一组固定的边距大小,也可以为每个部分返回不同的边距大小。
//section插入是仅应用于section中的items的页边距。
//它们表示页眉视图和第一行项目之间以及最后一行项目和页脚视图之间的距离。
//它们也表示单行items两侧的间距。它们不影响页眉或页脚本身的大小。
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView 
  layout:(UICollectionViewLayout*)collectionViewLayout 
      insetForSectionAtIndex:(NSInteger)section;
      
//如果不实现此方法,
//则流布局将使用其minimumLineSpacing属性中的值来设置线之间的间距。
//此方法的实现 可以为每个部分返回固定值 或 返回不同的间距值。
//对于 垂直滚动的网格,此值表示 连续行 之间的最小间距。
//对于 水平滚动的网格,此值表示 连续列 之间的最小间距。
//此间距 不适用于 页眉和第一行之间 或 最后一行和页脚之间的间距。
- (CGFloat)collectionView:(UICollectionView *)collectionView 
   layout:(UICollectionVie wLayout*)collectionViewLayout 
       minimumLineSpacingForSectionAtIndex:(NSInteger)section;
       
//如果不实现此方法,
//则流布局将使用其minimumInteritemSpacing属性中的值来设置项之间的间距。
//此方法的实现可以为每个部分返回固定值或返回不同的间距值。
//对于 垂直滚动的网格,此值表示  同一行中items之间 的最小间距。
//对于 水平滚动的网格,此值表示  同一列中items之间的 最小间距。
//该间距用于计算单行中可以容纳多少items,但在确定了items的数量之后,
//实际间距可能会向上调整。
- (CGFloat)collectionView:(UICollectionView *)collectionView 
  layout:(UICollectionViewLayout*)collectionViewLayout 
   minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

3、获取header 和 footer 大小

objectivec 复制代码
//如果不实现此方法,
//流布局将使用其headerReferenceSize属性中的值来设置header的大小。
//在布局期间,只有合适滚动方向的大小被使用。
//例如,对于垂直滚动方向,布局对象使用方法返回的高度值。
//(在这种情况下,页眉的宽度将设置为集合视图的宽度。)
//如果在滚动范围内的大小为0,则不添加header。
- (CGSize)collectionView:(UICollectionView *)collectionView 
    layout:(UICollectionViewLayout*)collectionViewLayout 
         referenceSizeForHeaderInSection:(NSInteger)section;
//如果不实现此方法,
//流布局将使用其footerReferenceSize属性中的值来设置footer的大小。
//在布局期间,只有合适滚动方向的大小被使用。
//例如,对于垂直滚动方向,布局对象使用方法返回的高度值。
//(在这种情况下,页眉的宽度将设置为集合视图的宽度。)
//如果在滚动范围内的大小为0,则不添加footer。
- (CGSize)collectionView:(UICollectionView *)collectionView 
    layout:(UICollectionViewLayout*)collectionViewLayout 
        referenceSizeForFooterInSection:(NSInteger)section;
UICollectionViewFlowLayoutInvalidationContext

流布局对象在需要使其内容失效以响应更改时创建该类的实例。您也可以在手动使流布局无效时创建实例。

UICollectionViewFlowLayoutInvalidationContext 继承UICollectionViewLayoutInvalidationContext

objectivec 复制代码
//一个布尔值,指示是否重新计算布局中items和views的大小。
//该属性的默认值为NO。如果由于更改任何items的大小而使布局无效,则将此属性设置为YES。
//当此属性设置为YES时,流布局对象将重新计算其items和views的大小,
//并根据需要查询委托对象以获得该信息。
@property (nonatomic) BOOL invalidateFlowLayoutDelegateMetrics; 

//一个布尔值,指示 是否重新计算布局中 items和views的布局属性。
//该属性的默认值为NO。如果在屏幕上的items的位置发生变化,则将此属性设置为YES。
//例如,当集合视图的边界在某种程度上发生改变并影响到 列或行中 items数量的变化时,
//流布局对象将此属性设置为YES。
//当此属性设置为YES时,流布局对象将为其items和views 重新计算布局属性。
//如果invalidateFlowLayoutDelegateMetrics属性被设置为NO,
//它将重新计算该信息,而不要求提供新的大小信息。
@property (nonatomic) BOOL invalidateFlowLayoutAttributes; 
相关推荐
风清扬_jd40 分钟前
Chromium 硬件加速开关c++
java·前端·c++
谢尔登2 小时前
【React】事件机制
前端·javascript·react.js
2401_857622662 小时前
SpringBoot精华:打造高效美容院管理系统
java·前端·spring boot
etsuyou2 小时前
Koa学习
服务器·前端·学习
Easonmax2 小时前
【CSS3】css开篇基础(1)
前端·css
粥里有勺糖3 小时前
视野修炼-技术周刊第104期 | 下一代 JavaScript 工具链
前端·javascript·github
大鱼前端3 小时前
未来前端发展方向:深度探索与技术前瞻
前端
昨天;明天。今天。3 小时前
案例-博客页面简单实现
前端·javascript·css
天上掉下来个程小白3 小时前
请求响应-08.响应-案例
java·服务器·前端·springboot
前端络绎3 小时前
初识 DT-SDK:基于 Cesium 的二三维一体 WebGis 框架
前端