UICollectionView
集合视图和TalbeView有许多相似之处, 和TableView不同的是, TableVIew是以行为单位, 每行拥有一个TableViewCell, 而集合视图是一一个item作为单位, 一行可以有多个item. 而每个Item的大小也可以不同, 通常需要自己重新定制.
集合视图和TableView相同的是, 可以设置分区数, 可以设置每个分区下的成员个数. 可以给每个分区设置表头 和表尾
和TableView不同, CollectionView需要一个布局格式类(UICollectionViewLayout)来设置CollectionView的界面框架布局.
在框架样式上, CollectionView比TableView要更加复杂.
关键属性
@property (nonatomic, retain) UICollectionViewLayout *collectionViewLayout;
@property (nonatomic, assign) id <UICollectionViewDelegate> delegate;
@property (nonatomic, assign) id <UICollectionViewDataSource> dataSource;
其中collectionViewLayout是用于控制集合视图的框架布局.
delegate是响应集合视图的手势交互操作的代理对象
dataSource是控制集合视图具体内容的代理代理对象
UICollectionViewFlowLayout类
UICollectionViewLayout是一个抽象类, 具体功能是有它的子类实现.
UICollectionViewFlowLayout是系统提供的一个UICollectionViewLayout的子类 可实现网状结构的布局.
一般情况下, 用UICollectionViewFlowLayout即可应对需求.
布局相关的属性
- 控制行与行之间的最小间距
@property (nonatomic) CGFloat minimumLineSpacing;
- 控制列与列之间的最小间距
@property (nonatomic) CGFloat minimumInteritemSpacing;
- 设置每个item的大小
@property (nonatomic) CGSize itemSize;
- 限制item的大小
@property (nonatomic) CGSize estimatedItemSize;
- 设置集合视图滚动的方向
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
分为横向UICollectionViewScrollDirectionHorizontal
和纵向UICollectionViewScrollDirectionVertical
两种
默认是纵向的. - 设置表头的大小
@property (nonatomic) CGSize headerReferenceSize;
注意, 表头大小的宽度和高度是受集合视图滚动方向影响的.
当集合视图的滚动方向为纵向的时候, 表头的宽度设置不会影响表头的实际显示宽度
当集合视图的滚动方向是横向的时候, 表头的高度设置不会影响表头的实际显示高度 - 设置表尾的大小
@property (nonatomic) CGSize footerReferenceSize;
设置限制同表头 设置分区内边距
@property (nonatomic) UIEdgeInsets sectionInset;
返回值的结构如下typedef struct UIEdgeInsets { CGFloat top, left, bottom, right; } UIEdgeInsets;
作用是设置一个分区内的所有处于边缘的item 距离对应方向的边缘的距离.
创建方法如下UIEdgeInsets UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right) { UIEdgeInsets insets = {top, left, bottom, right}; return insets; }
UICollectionViewDelegate协议
常用方法如下:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
响应某个item的点击时间, item的索引indexPath和TableView中的indexPath相同.
另外的, UICollectionViewFlowLayout类中也给UICollectionViewDelegate延展了一些新的协议方法
主要内容如下:
@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>
@optional
// 设置某个item的大小, 若已用属性itemSize设置过, 依然已此方法为准, 下同
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
// 设置分区的内边距
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
// 设置某个分区内的最小行边距
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
// 设置某个分区内的最小列边距
- (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;
@end
UICollectionViewDataSource协议
必须重写的方法
// 某个分区下item的个数, 若没有设置分区个数, 默认为1
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
// 设置某个item的具体样式, 具体样式可以自定义一个UICollectionViewCell的子类来实现
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
和TableViewCell相似, UICollectionViewCell也有重用机制. 但是两者在书写上略有不同.
UICollectionViewCell需要事先注册, 并给定标识符. 在cellForItemAtIndexPath方法中必须使用
-dequeueReusableCellWithReuseIdentifier:forIndexPath:
方法获取重用池中的cell. 同时本方法的作用还有若是没有获取到cell会自动创建一个cell. 且自动创建cell的时候会触发cell的initWithFrame:方法
注册语句如下:
// 若是需要用到自定义cell, 就填写自定义cell的类名, 注意注册的标识符和取出重用标识符一致.
// 若是需要用到多个自定义cell, 则需要执行多个注册语句. 注意标识符不能重复.
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
// 从重用池中取出cell
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
// 可以利用indexPath判断当前需要取出的cell是哪个类的cell. 注意此处出现的标识符必须是已经注册过的标识符, 且标识符和cell所属的类必须对应.
可选择重写方法
// 设置分区数的方法
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
// 设置表头和表尾样式的方法, 通过kind属性来判断当前是表头还是表尾
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
// kind值分为两种:
// UICollectionElementKindSectionHeader 和 UICollectionElementKindSectionFooter
// 前者表示表头, 后者表示表尾
表头表尾同样有重用机制. 和cell一样, 也需要先进行注册以后才能使用
表头表尾是属于UICollectionReusableView(可重用视图类)或其子类的对象
系统自身的表头表尾是什么都没有的, 若需要添加表头表尾需要自己自定义UICollectionReusableView的子类.
若要显示表头表尾, 必须要给定一个表头表尾的大小.
// 注册表头
[collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
// 注册表尾
[collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer"];
// 若要使用自定义的表头表尾, 只要注册对应自定义类名即可.
// 若要使用多种样式的表头或表尾, 就需要多个注册表头或者表尾的语句
// 重用表头表尾的方法
// 创建表头表尾
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
// 判断返回表头类型 还是表尾类型
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
// 表头
// 去重用池里找 判断一下 有就用 没有就创建
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath];
headerView.backgroundColor = [UIColor magentaColor];
return headerView;
} else {
// 表尾
UICollectionReusableView *rootView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer" forIndexPath:indexPath];
rootView.backgroundColor = [UIColor yellowColor];
return rootView;
}
}