UICollectionView 介绍

简介

UICollectionView用于展示集合视图,布局更加灵活; UICollectionView 继承于 UIScrollView,UICollectionViewDelegate 协议继承于 UIScrollViewDelegate 协议。所以在使用 UICollectionView 的时候,可以直接使用 UIScrollView 的各个属性方法。

内置的UICollectionViewFlowLayout提供了多行多列的展示方式,UICollectionViewDataSouce提供了数据源协议,UICollectionViewDelegate提供了UI交互的先关协议,使用UICollectionView我们可以用很少的代码就可以实现很多复杂的效果

API介绍

UIScrollView相关

UIScrollViewDelegate 的方法:
  • scrollViewDidScroll::在任何 contentOffset 发生改变的时刻调用。可以用来自定义一个下拉刷新控件。
  • scrollViewWillBeginDragging::在 scrollView 被拖拽的时候调用。可以在此时暂停一些复杂操作以保证滑动的流畅性。
  • scrollViewWillEndDragging:withVelocity:targetContentOffset::在用户结束拖拽并抬起手指后调用。第二个参数表示结束拖动时的速度。第三个参数表示最终结束滚动时的 contentOffset 值,这里是一个 CGPoint 的指针,我们可以让其指向一个新的 CGPoint 以自由控制最终的 contentOffset 大小。除了让我们改变最终停止的位置,这个方法还可以使我们能够对要展示区域的数据提前进行准备。
  • scrollViewShouldScrollToTop::在用户点击状态栏的时候回调,返回 YES 允许 scrollView 滚动到顶端。
  • scrollViewDidScrollToTop::在点击顶部状态栏并且滚动到顶端后回调。
  • scrollViewDidEndDecelerating::在结束减速动画的时候调用。可以用来继续之前暂停的复杂操作。

UICollectionView相关

基础

UITableView的创建只需要设置frame即可使用 UICollectionView除了需要frame,还需要一个布局参数Layout;

UICollectionView包含三个部分,它们都是UIView的子类:

  • Cells 用于展示内容的主体,对于不同的cell可以指定不同尺寸和不同的内容
  • 追加视图(Supplementary Views) 如果你对UITableView比较熟悉的话,可以理解为每个Section的Header或者Footer,用来标记每个section的view
  • 装饰视图(Decoration Views) 这是每个section的背景,比如iBooks中的书架就是这个
//直接初始化方法,需要提供一个Layout
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout NS_DESIGNATED_INITIALIZER;
//从nib文件直接初始化
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
//当前Layout
@property (nonatomic, strong) UICollectionViewLayout *collectionViewLayout;
//用户交互Delegate
@property (nonatomic, weak, nullable) id <UICollectionViewDelegate> delegate;
//UI的数据源DataSource
@property (nonatomic, weak, nullable) id <UICollectionViewDataSource> dataSource;

//iOS10新增加的Pre-Fetching预加载协议
@property (nonatomic, weak, nullable) id<UICollectionViewDataSourcePrefetching> prefetchDataSource NS_AVAILABLE_IOS(10_0);
//是否允许预加载
@property (nonatomic, getter=isPrefetchingEnabled) BOOL prefetchingEnabled NS_AVAILABLE_IOS(10_0);
//背景图片,自动根据collectionView的大小调整
@property (nonatomic, strong, nullable) UIView *backgroundView;

//注册UICollectionViewCell,或其子类,并且提供一个复用标识符,在runtime的时候会初始化这个对象
- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
//通过nib文件注册复用cell
- (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
//通过Class注册补充视图,并且指定补充视图的种类
- (void)registerClass:(nullable Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
//通过nib文件注册补充视图
- (void)registerNib:(nullable UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;

//从复用队列通过指定Identifier获取复用cell
- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;
//从复用队列通过指定Identifier获取复用ReusableView
- (__kindof UICollectionReusableView *)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;

//是否允许items选中,默认YES
@property (nonatomic) BOOL allowsSelection; // default is YES
//是否允许items多选,默认NO
@property (nonatomic) BOOL allowsMultipleSelection; // default is NO

//返回选中的index paths,返回nil或者NSArray
#if UIKIT_DEFINE_AS_PROPERTIES
@property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForSelectedItems;
#else
- (nullable NSArray<NSIndexPath *> *)indexPathsForSelectedItems;
#endif

//选中和解选indexPath对应item,可指定动画和UICollectionViewScrollPosition
- (void)selectItemAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition;
- (void)deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;

//刷新数据
- (void)reloadData;

//切换当前collectionView的layout
- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated;
//切换当前collectionView的layout,配置完成之后的block(iOS7之后可用)
- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
//下面这些方法更加强大,我们可以对布局更改后的动画进行设置
//这个方法传入一个布局策略layout,系统会开始进行布局渲染,返回一个UICollectionViewTransitionLayout对象
//这个UICollectionViewTransitionLayout对象管理动画的相关属性,我们可以进行设置
- (UICollectionViewTransitionLayout *)startInteractiveTransitionToCollectionViewLayout:(UICollectionViewLayout *)layout completion:(nullable UICollectionViewLayoutInteractiveTransitionCompletion)completion NS_AVAILABLE_IOS(7_0);
//准备好动画设置后,我们需要调用下面的方法进行布局动画的展示,之后会调用上面方法的block回调
//layout切换过渡完成
- (void)finishInteractiveTransition NS_AVAILABLE_IOS(7_0);
//取消过渡切换layout
- (void)cancelInteractiveTransition NS_AVAILABLE_IOS(7_0);

//下面是UICollectionView的状态信息

//返回section的数量
#if UIKIT_DEFINE_AS_PROPERTIES
@property (nonatomic, readonly) NSInteger numberOfSections;
#else
- (NSInteger)numberOfSections;
#endif
//返回对应section中item的数量
- (NSInteger)numberOfItemsInSection:(NSInteger)section;
//返回对应indexPath的item的LayoutAttributes
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
//返回对应indexPath的ReuseView的LayoutAttributes
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
//返回对应point的indexPath
- (nullable NSIndexPath *)indexPathForItemAtPoint:(CGPoint)point;
//返回对应cell的indexPath
- (nullable NSIndexPath *)indexPathForCell:(UICollectionViewCell *)cell;
//返回对应indexPath的cell
- (nullable UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath;

//返回collectionView当前可见的item数组和可见item的indexPath数组
#if UIKIT_DEFINE_AS_PROPERTIES
@property (nonatomic, readonly) NSArray<__kindof UICollectionViewCell *> *visibleCells;
@property (nonatomic, readonly) NSArray<NSIndexPath *> *indexPathsForVisibleItems;
#else
- (NSArray<__kindof UICollectionViewCell *> *)visibleCells;
- (NSArray<NSIndexPath *> *)indexPathsForVisibleItems;
#endif

//返回对应indexPath的ReuseView(iOS9之后可用)
- (nullable UICollectionReusableView *)supplementaryViewForElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
//返回collectionView当前可见的ReuseView数组
- (NSArray<UICollectionReusableView *> *)visibleSupplementaryViewsOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(9_0);
//返回collectionView当前可见ReuseView的indexPath数组
- (NSArray<NSIndexPath *>
   *)indexPathsForVisibleSupplementaryElementsOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(9_0);

//下面是UICollectionView的交互相关信息

//滚动到指定的indexPath
- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated;

//插入一个section
- (void)insertSections:(NSIndexSet *)sections;
//删除一个section
- (void)deleteSections:(NSIndexSet *)sections;
//刷新一个section
- (void)reloadSections:(NSIndexSet *)sections;
//移动一个section到另外一个section
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;

//插入一个section
- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
//删除一个section
- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
//刷新一个section
- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;
//移动一个indexPath的item到另一个indexPath的item
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;

//一次性操作插入,删除,刷新,移动操作
//Animates multiple insert, delete, reload, and move operations as a group
- (void)performBatchUpdates:(void (^ __nullable)(void))updates completion:(void (^ __nullable)(BOOL finished))completion; // allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable.

// 排序相关

//是否允许排序,默认YES(iOS9之后有效)
- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
//更新item的位置
- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition NS_AVAILABLE_IOS(9_0);
//移动item到新的position
- (void)endInteractiveMovement NS_AVAILABLE_IOS(9_0);
//回复item到原始的position
- (void)cancelInteractiveMovement NS_AVAILABLE_IOS(9_0);

//是否记住最后操作的indexPath,默认NO
@property (nonatomic) BOOL remembersLastFocusedIndexPath NS_AVAILABLE_IOS(9_0);

//UICollectionView 补充 的indexPath
@interface NSIndexPath (UICollectionViewAdditions)
//初始化indexPath
+ (instancetype)indexPathForItem:(NSInteger)item inSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
//返回IndexPath的item
@property (nonatomic, readonly) NSInteger item NS_AVAILABLE_IOS(6_0);
@end

//UICollectionViewDataSource数据源协议
@protocol UICollectionViewDataSource <NSObject>

@required
//配置UICollectionView的section对应item的数量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;

//配置UICollectionView的item,需要提前注册
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

@optional
//配置UICollectionView的section数量
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;

//配置UICollectionView的ReuseView,需要提前注册
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;

//是否可以移动
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
//移动indexPath的item到另一个indexPath
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath NS_AVAILABLE_IOS(9_0);

@end

//UICollectionViewDelegate UI交互协议
@protocol UICollectionViewDelegate <UIScrollViewDelegate>

@optional
//是否允许高亮
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
//已经高亮
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
//取消高亮
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
//是否允许选中
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
//是否允许解选
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; // called when the user taps on an already-selected item in multi-select mode
//已经选中
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
//已经解选
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

//将要显示item(iOS8之后可用)
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
//将要显示SupplementaryView(iOS8之后可用)
- (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
//已经显示item
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
//已经显示SupplementaryView
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;

//是否允许展示copy/paste Menu
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;
//是否可以执行SEL
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;
//执行SEL
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;

@end
  
UICollectionViewLayout

UICollectionViewLayout是UICollectionView的精髓, 通过它可以构建出各种各样的布局;

它负责了将各个cell、Supplementary View和Decoration Views进行组织,为它们设定各自的属性,包括但不限于:

  • 位置
  • 尺寸
  • 透明度
  • 层级关系
  • 形状
  • 等等等等…
  • Layout决定了UICollectionView是如何显示在界面上的。在展示之前,一般需要生成合适的UICollectionViewLayout子类对象,并将其赋予CollectionView的collectionViewLayout属性。
系统子类UICollectionViewFlowLayout
  • UICollectionViewFlowLayout是系统自带的简单的网格布局,用来展示多行多列数据。可以通过属性的配置来控制全局item的大小。

    • 首先一个重要的属性是itemSize,它定义了每一个item的大小。通过设定itemSize可以全局地改变所有cell的尺寸,如果想要对某个cell制定尺寸,可以使用-collectionView:layout:sizeForItemAtIndexPath:方法。
    • 间隔 可以指定item之间的间隔和每一行之间的间隔,和size类似,有全局属性,也可以对每一个item和每一个section做出设定:
      • @property (CGSize) minimumInteritemSpacing
      • @property (CGSize) minimumLineSpacing
      • -collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
      • -collectionView:layout:minimumLineSpacingForSectionAtIndex:
    • 滚动方向 由属性scrollDirection确定scroll view的方向,将影响Flow Layout的基本方向和由header及footer确定的section之间的宽度
      • UICollectionViewScrollDirectionVertical
      • UICollectionViewScrollDirectionHorizontal
    • Header和Footer尺寸 同样地分为全局和部分。需要注意根据滚动方向不同,header和footer的高和宽中只有一个会起作用。垂直滚动时section间宽度为该尺寸的高,而水平滚动时为宽度起作用,如图。
      • @property (CGSize) headerReferenceSize
      • @property (CGSize) footerReferenceSize
      • -collectionView:layout:referenceSizeForHeaderInSection:
      • -collectionView:layout:referenceSizeForFooterInSection:
    • 缩进
      • @property UIEdgeInsets sectionInset;
      • -collectionView:layout:insetForSectionAtIndex:
    //设置item行之间的最小间隔
    @property (nonatomic) CGFloat minimumLineSpacing;
    //设置item之间的最小间隔
    @property (nonatomic) CGFloat minimumInteritemSpacing;
    //设置item的大小
    @property (nonatomic) CGSize itemSize;
    //设置item大小的近似值,默认是CGSizeZero(iOS8之后有效)
    @property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:
    //设置滚动方向
    @property (nonatomic) UICollectionViewScrollDirection scrollDirection; // default is UICollectionViewScrollDirectionVertical
    //设置头部引用视图的大小,对于垂直滚动时,宽不起作用,高度起作用;水平滚动相反
    @property (nonatomic) CGSize headerReferenceSize;
    ////设置尾部引用视图的大小
    @property (nonatomic) CGSize footerReferenceSize;
    //设置section的上下左右留白
    @property (nonatomic) UIEdgeInsets sectionInset;
    
    //下面两个属性在iOS9之后可用,用来设置是否粘贴头部在屏幕的头部和尾部在屏幕的尾部
    @property (nonatomic) BOOL sectionHeadersPinToVisibleBounds NS_AVAILABLE_IOS(9_0);
    @property (nonatomic) BOOL sectionFootersPinToVisibleBounds NS_AVAILABLE_IOS(9_0);
    
    /** -----------------当然也可以细致的配置每一个item大小,这时需要实现UICollectionViewDelegateFlowLayout协议 */
    
    //设置具体indexPath的item大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
    //设置具体section的上下左右留白
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
    //设置行最小间隔
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
    //设置item间最小间隔
    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
    //设置头部引用视图的大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
    //设置尾部引用视图的大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;
    
自定义UICollectionViewLayout
  • 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以考虑自定义layout。UICollectionViewLayout是UICollectionView的精髓,是区别于UITableView的一个重要特征,UICollectionView通过 UICollectionViewLayout 返回的 UICollectionViewLayoutAttributes 来布局每一个item。子类通过重写UICollectionViewLayout中的方法可以实现各种各样的布局样式,也可以使用另外一套布局来更新当前布局样式;
0000000000000000000000  - UICollectionViewLayoutAttributes的头文件内容

//设置item的frame
@property (nonatomic) CGRect frame;
//设置item的center
@property (nonatomic) CGPoint center;
//设置item的size
@property (nonatomic) CGSize size;
//设置item的transform3D
@property (nonatomic) CATransform3D transform3D;
//设置item的bounds
@property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0);
//设置item的transform
@property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0);
//设置item的alpha
@property (nonatomic) CGFloat alpha;
//设置item的zIndex,默认是0和其他item在同一平面,设置小于0,在其他item下面
@property (nonatomic) NSInteger zIndex; // default is 0
//设置item的hidden状态,通常为NO
@property (nonatomic, getter=isHidden) BOOL hidden;
//设置item的indexPath
@property (nonatomic, strong) NSIndexPath *indexPath;
//设置当前元素的类别,是个美剧变量 cell/supplementaryView/decorationView
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
//展示的元素类型,如果是cell 则为nil
@property (nonatomic, readonly, nullable) NSString *representedElementKind; // nil when representedElementCategory is UICollectionElementCategoryCell
 
//指定indexPath的cell的layoutAttributes
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
//指定indexPath的supplementaryView的layoutAttributes
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
//指定indexPath的decorationView的layoutAttributes
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;

0000000000000000000000 -   下面是UICollectionViewLayout相关的API:

//构造函数
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

//当前layout服务的collectionView对象
@property (nullable, nonatomic, readonly) UICollectionView *collectionView;

//验证当前layout,会触发collectionView的reloadData
- (void)invalidateLayout;
//验证当前layout,并且提供一个验证的上下文,也会触发collectionView的reloadData
- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context NS_AVAILABLE_IOS(7_0);

//注册decorationView用Class/nib
- (void)registerClass:(nullable Class)viewClass forDecorationViewOfKind:(NSString *)elementKind;
- (void)registerNib:(nullable UINib *)nib forDecorationViewOfKind:(NSString *)elementKind;


0000000000000000000000 - 自定义layout需要关注的API:

//自定义layoutAttributesClass和invalidationContextClass在需要的时候
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) Class layoutAttributesClass; // override this method to provide a custom class to be used when instantiating instances of UICollectionViewLayoutAttributes
@property(class, nonatomic, readonly) Class invalidationContextClass NS_AVAILABLE_IOS(7_0); // override this method to provide a custom class to be used for invalidation contexts
#else
+ (Class)layoutAttributesClass; // override this method to provide a custom class to be used when instantiating instances of UICollectionViewLayoutAttributes
+ (Class)invalidationContextClass NS_AVAILABLE_IOS(7_0); // override this method to provide a custom class to be used for invalidation contexts
#endif

//UICollectionView在第一次layout的时候会调用prepareLayout,并且在当前layout invalidated之后也会调用这个方法,子类需要重写此方法完成相关配置
- (void)prepareLayout;

//UICollectionView会调用下面四个方法完成相关的配置信息

//返回给定rect内的layoutAttributes数组
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
//返回给定indexPath的item的layoutAttributes
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
//返回给定indexPath的supplementaryView的layoutAttributes,如果有
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
//返回给定indexPath的decorationView的layoutAttributes,如果有
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;

//是否验证给定的bounds,会引起UICollectionView刷新layout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

//返回给定bounds的无效上下文
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds NS_AVAILABLE_IOS(7_0);

//是否验证layoutAttributes
- (BOOL)shouldInvalidateLayoutForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes NS_AVAILABLE_IOS(8_0);
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes NS_AVAILABLE_IOS(8_0);

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset NS_AVAILABLE_IOS(7_0); // a layout can return the content offset to be applied during transition or update animations

//返回collectionView的contentSize
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly) CGSize collectionViewContentSize; // Subclasses must override this method and use it to return the width and height of the collection view’s content. These values represent the width and height of all the content, not just the content that is currently visible. The collection view uses this information to configure its own content size to facilitate scrolling.
#else
- (CGSize)collectionViewContentSize; // Subclasses must override this method and use it to return the width and height of the collection view’s content. These values represent the width and height of all the content, not just the content that is currently visible. The collection view uses this information to configure its own content size to facilitate scrolling.
#endif


0000000000000000000000 -  刷新layout需要关注的 API:

- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;
- (void)finalizeCollectionViewUpdates; // called inside an animation block after the update

- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds; // UICollectionView calls this when its bounds have changed inside an animation block before displaying cells in its new bounds
- (void)finalizeAnimatedBoundsChange; // also called inside the animation block

// UICollectionView calls this when prior the layout transition animation on the incoming and outgoing layout
- (void)prepareForTransitionToLayout:(UICollectionViewLayout *)newLayout NS_AVAILABLE_IOS(7_0);
- (void)prepareForTransitionFromLayout:(UICollectionViewLayout *)oldLayout NS_AVAILABLE_IOS(7_0);
- (void)finalizeLayoutTransition NS_AVAILABLE_IOS(7_0);  // called inside an animation block after the transition


// This set of methods is called when the collection view undergoes an animated transition such as a batch update block or an animated bounds change.
// For each element on screen before the invalidation, finalLayoutAttributesForDisappearingXXX will be called and an animation setup from what is on screen to those final attributes.
// For each element on screen after the invalidation, initialLayoutAttributesForAppearingXXX will be called and an animation setup from those initial attributes to what ends up on screen.
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;

// These methods are called by collection view during an update block.
// Return an array of index paths to indicate views that the layout is deleting or inserting in response to the update.
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(7_0);
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForDecorationViewOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(7_0);
- (NSArray<NSIndexPath *> *)indexPathsToInsertForSupplementaryViewOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(7_0);
- (NSArray<NSIndexPath *> *)indexPathsToInsertForDecorationViewOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(7_0);

0000000000000000000000 - 排序需要关注的layout API:
- (NSIndexPath *)targetIndexPathForInteractivelyMovingItem:(NSIndexPath *)previousIndexPath withPosition:(CGPoint)position NS_AVAILABLE_IOS(9_0);
- (UICollectionViewLayoutAttributes *)layoutAttributesForInteractivelyMovingItemAtIndexPath:(NSIndexPath *)indexPath withTargetPosition:(CGPoint)position NS_AVAILABLE_IOS(9_0);

- (UICollectionViewLayoutInvalidationContext *)invalidationContextForInteractivelyMovingItems:(NSArray<NSIndexPath *> *)targetIndexPaths withTargetPosition:(CGPoint)targetPosition previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths previousPosition:(CGPoint)previousPosition NS_AVAILABLE_IOS(9_0);
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:(NSArray<NSIndexPath *> *)indexPaths previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths movementCancelled:(BOOL)movementCancelled NS_AVAILABLE_IOS(9_0);
UICollectionViewDataSouce

提供了数据源协议

  • section的数量 -numberOfSectionsInCollection:
  • 某个section里有多少个item -collectionView:numberOfItemsInSection:
  • 对于某个位置应该显示什么样的cell -collectionView:cellForItemAtIndexPath:
@required
/* 设置容器视图各个组都有多少个Cell方块 */
- (NSInteger)collectionView:(UICollectionView *)collectionView 
     numberOfItemsInSection:(NSInteger)section;
/* 设置Cell方块视图,类似于UITableViewCell的设置 */
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath;
@optional
/* 容器视图有多少个组,默认返回1 */
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
/* 设置顶部视图和底部视图,通过kind参数分辨是设置顶部还是底部 */
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView 
           viewForSupplementaryElementOfKind:(NSString *)kind 
                                 atIndexPath:(NSIndexPath *)indexPath;

UICollectionViewDelegate

数据无关的view的外形啊,用户交互啊什么的,由UICollectionViewDelegate来负责:

  • cell的高亮
  • cell的选中状态
  • 可以支持长按后的菜单
  • 我们使用更多的是UICollectionViewDelegate子协议UICollectionViewDelegateFlowLayout 该协议不仅包含父协议所有方法,还可以进行一些布局设置
// UICollectionViewDelegateFlowLayout的常用布局方法
/* 设置每个方块的尺寸大小 */
- (CGSize)collectionView:(UICollectionView *)collectionView 
                  layout:(UICollectionViewLayout*)collectionViewLayout 
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
/* 设置方块视图和边界的上下左右间距 */
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView 
                        layout:(UICollectionViewLayout*)collectionViewLayout 
        insetForSectionAtIndex:(NSInteger)section;

参考:

UICollectionView之自定义Layout

iOS学习笔记33 UICollectionView入门

UICollectionView基础API笔记及应用实践

UICollectionView 使用方法总结