简介
- 继承自 UIScrowView
- 从 iOS 6 开始引入使用的
- Cell 只能通过注册来确定重用标识符
- 每个格子都是个
UICollectionViewCell
每行显示多少个 Cell,取决于UICollectionView
的宽度 能容纳多少 Cell
UICollectionView 和 UITableView 的比较
- UITableViewController 的
self.view == self.tableview;
UICollectionViewController 的self.view != self.collectionView;
- UITableView 的滚动方式只能是垂直方向
UICollectionView 既可以垂直滚动,也可以水平滚动
- UITableView 的 Cell 是系统自动布局的,不需要自定义
-
UICollectionView
的 Cell 必须自定义布局
在创建UICollectionView
的时候必须传递一个布局参数
系统提供并实现了一个布局样式:UICollectionViewFlowLayout
流水布局
1. 组成结构
可见部分
-
UICollectionView
内容显示的主视图:类似于 UITableView -
UICollectionViewCell
用于展示内容的主体:对于不同的 Cell 可以指定不同的尺寸和内容 -
Supplementary View
附加视图:可以理解为 UITableView 每个 Section 的 HeaderView 和 FooterView -
Decoration View
装饰视图:这是每个 section 的背景视图,用于装饰该 section
不可见部分
-
UICollectionViewLayout
用来处理cell在屏幕上的布局
使用一系列的代理方法在 UICollectionView 上约束 Cell 的摆放,而且布局效果可以在运行时,随时改变
2. 自定义布局
布局的函数调用流程
- 白框代表 CollectionView 在布局时使用的方法
- 橙框代表 CollectionView 的状态
- 绿框代表 CollectionView 的使用者调用的方法
简介
-
UICollectionViewLayout 「抽象类」
会对屏幕上的 Cells 进行组织布局
首先要继承
- 继承 UICollectionViewLayout 或 UICollectionViewFlowLayout 流水布局
- 如果 继承
UICollectionViewLayout
,要实现切换布局功能时必须实现layoutAttributesForItemAtIndexPath:
方法 - 在
layoutAttributesForItemAtIndexPath:
方法中执行prepareLayout
方法的布局方式
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
I. 预先设置布局样式
作用
-
prepareLayout
用来做一些初始化操作 -
prepareLayout
执行前,collectionView
相关的尺寸等已经确定下来,供prepareLayout
使用
// 注意:重写本方法时,必须调用父类方法
- (void)prepareLayout;
II. 在给定矩形范围内设置布局属性
作用
- 当
collectionView
滚动时调用该方法 - 1 个 Cell 对应 1 个
UICollectionViewLayoutAttributes
对象 - 返回值
UICollectionViewLayoutAttributes
对象
决定了 Rect 范围内 Cell 的布局方式「frame 等」
决定了 Supplementary View、Decoration View 的布局方式
// UICollectionViewLayoutAttributes 的属性
@property (nonatomic) CGPoint center; // view 在 CollectionView 的坐标系统中的 中心
@property (nonatomic) CGRect frame; // view 在 CollectionView 的坐标系统中的 具体位置
@property (nonatomic) CGSize size; // view 的大小
@property (nonatomic) CGRect bounds; // view 的尺寸
@property (nonatomic) CGFloat alpha; // 透明度
@property (nonatomic) NSInteger zIndex; // 子视图的层级「默认 0」
@property (nonatomic) CATransform3D transform3D; // 用来旋转,缩放的属性
@property (nonatomic) CGAffineTransform transform; // 用来形装改变
@property (nonatomic, getter=isHidden) BOOL hidden; // view 是否隐藏「如果隐藏 view 可能会不产生」
// rect:和 collectionView 的坐标系一致,控制 collectionView 部分内容显示在屏幕上的矩形大小
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
III. 确保每次滚动时重新布局
作用
- 表示 collectionView 滚动时「显示的范围发生改变时」,是否废弃当前的布局
- 一旦废弃当前的布局,就会依次调用
prepareLayout
、layoutAttributesForElementsInRect:
方法
// 默认 返回 NO
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
IV. 确定滚动结束后的布局
作用
- 滑动 collectionView 松开后调用
- 返回 collectionView 停止滚动时最终的偏移量
contentOffset
// proposedContentOffset:collectionView 停止滚动时最终的偏移量
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset;
// velocity:滚动速率,通过这个参数可以了解滚动的方向
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
3. 总体步骤
原理
- UICollectionView 向
UICollectionViewLayout
询问布局
询问时,layout 对象会创建UICollectionViewLayoutAttributes
实例 - 1 个
UICollectionViewLayoutAttributes
对象管理着 1 个对应的item layout
相关信息「一对一关系」
步骤
- 注册 Cell「告诉 collectionView 将来创建那种标识的 Cell」
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellID"];
- 从缓存池中取出 Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellID" forIndexPath:indexPath];
return cell;
}
- 重写 init 方法,创建布局参数「必须传入 非空布局,否则会报错」
// UICollectionViewFlowLayout 流水布局的内部成员属性有以下:
@property (nonatomic) CGFloat minimumLineSpacing; // Cell 之间的垂直间距
@property (nonatomic) CGFloat minimumInteritemSpacing; // Cell 之间的水平间距
@property (nonatomic) CGSize itemSize; // Cell 的尺寸
@property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0);
@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // 滚动方向「默认竖直方向」
@property (nonatomic) CGSize headerReferenceSize; // 每一组 header的大小
@property (nonatomic) CGSize footerReferenceSize; // 每一组 footer的大小
@property (nonatomic) UIEdgeInsets sectionInset; // UICollectionView 四周的内边距
- (id)init {
// 流水布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 10;
layout.sectionInset = UIEdgeInsetsMake(layout.minimumLineSpacing, 0, 0, 0);
return [super initWithCollectionViewLayout:layout];
}
- 实现数据源方法
@optional
// 返回每个组的 Cell 的数量「每个组的数量相同时使用」
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
@required
// 返回 给定组的 Cell 的数量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
// 返回 给定组号和组中序号 的 Cell 对象
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- 实现代理方法「Optional」
@optional // 所有代理方法都是可选的
// 点击了一个 Cell 后调用
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;