UICollectionView基础文章目录UICollectionView基础一、它到底是什么1. 核心三要素2. 必须遵守的协议3. 核心机制复用池二、第一步创建自定义 Cell三、第二步ViewController 完整代码四、自定义Layout实现瀑布流五、属性与方法一、它到底是什么1. 核心三要素UICollectionView展示在屏幕上的列表容器能滚动、放很多 cellUICollectionViewCell列表里每一个格子 / 卡片UICollectionViewLayout布局规则决定 cell 多大、怎么排、间距多少2. 必须遵守的协议UICollectionViewDataSource提供数据多少个、显示什么UICollectionViewDelegateFlowLayout控制布局、点击事件3. 核心机制复用池屏幕只显示 10 个 cell滑出屏幕的 cell → 放进复用池新进入屏幕的 cell → 从复用池取二、第一步创建自定义 Cell#importUIKit/UIKit.hinterfaceMyCollectionViewCell:UICollectionViewCell// 暴露给外面用的控件property(nonatomic,strong)UILabel*titleLabel;property(nonatomic,strong)UIImageView*iconImageView;end#importMyCollectionViewCell.himplementationMyCollectionViewCell// 初始化 Cell-(instancetype)initWithFrame:(CGRect)frame{self[superinitWithFrame:frame];if(self){// 背景self.backgroundColor[UIColor whiteColor];self.layer.cornerRadius8;self.layer.masksToBoundsYES;// 图片_iconImageView[[UIImageView alloc]initWithFrame:CGRectMake(10,10,60,60)];_iconImageView.backgroundColor[UIColor lightGrayColor];_iconImageView.contentModeUIViewContentModeScaleAspectFill;_iconImageView.clipsToBoundsYES;[self.contentView addSubview:_iconImageView];// 文字_titleLabel[[UILabel alloc]initWithFrame:CGRectMake(10,80,80,20)];_titleLabel.font[UIFont systemFontOfSize:14];_titleLabel.textAlignmentNSTextAlignmentCenter;[self.contentView addSubview:_titleLabel];}returnself;}end三、第二步ViewController 完整代码#importUIKit/UIKit.hinterfaceViewController:UIViewControllerend#importViewController.h#importMyCollectionViewCell.h// 1. 遵守协议interfaceViewController()UICollectionViewDataSource,UICollectionViewDelegateFlowLayoutproperty(nonatomic,strong)UICollectionView*collectionView;property(nonatomic,strong)NSArray*dataArray;// 数据endimplementationViewController-(void)viewDidLoad{[superviewDidLoad];self.view.backgroundColor[UIColor whiteColor];// 模拟数据self.dataArray[苹果,香蕉,西瓜,橙子,葡萄,梨子,桃子,菠萝,草莓,芒果,榴莲,火龙果];// 2. 创建布局 LayoutUICollectionViewFlowLayout*layout[[UICollectionViewFlowLayout alloc]init];// 滚动方向垂直/水平layout.scrollDirectionUICollectionViewScrollDirectionVertical;// cell 大小layout.itemSizeCGSizeMake(100,120);// 横向间距cell 与 cell 左右layout.minimumInteritemSpacing10;// 纵向间距行与行之间layout.minimumLineSpacing15;// 整个列表的内边距上、左、下、右layout.sectionInsetUIEdgeInsetsMake(20,20,20,20);// 3. 创建 CollectionViewself.collectionView[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];self.collectionView.backgroundColor[UIColor groupTableViewBackgroundColor];// 设置数据源和代理self.collectionView.dataSourceself;self.collectionView.delegateself;[self.view addSubview:self.collectionView];// 4. 注册自定义 Cell必须[self.collectionView registerClass:[MyCollectionViewCell class]forCellWithReuseIdentifier:MyCellID];}#pragmamark-必须实现的数据源方法// 每组多少个 cell-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{returnself.dataArray.count;}// 生成/复用 cell-(UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath{// 从复用池取 cell核心MyCollectionViewCell*cell[collectionView dequeueReusableCellWithReuseIdentifier:MyCellIDforIndexPath:indexPath];// 给 cell 赋值NSString*textself.dataArray[indexPath.item];cell.titleLabel.texttext;// 随机颜色cell.backgroundColor[UIColor colorWithHue:arc4random()%256/255.0saturation:0.5brightness:0.9alpha:1];returncell;}#pragmamark-常用代理方法// 点击 cell-(void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath{// 取消选中高亮[collectionView deselectItemAtIndexPath:indexPath animated:YES];NSLog(点击了%,self.dataArray[indexPath.item]);}// 每个 cell 自定义大小-(CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath{returnCGSizeMake(100,120);}end四、自定义Layout实现瀑布流#importUIKit/UIKit.hclassWaterfallLayout;protocolWaterfallLayoutDelegateNSObject// 代理返回每个cell的高度-(CGFloat)waterfallLayout:(WaterfallLayout*)layout heightForItemAtIndexPath:(NSIndexPath*)indexPath;endinterfaceWaterfallLayout:UICollectionViewLayoutproperty(nonatomic,weak)idWaterfallLayoutDelegatedelegate;property(nonatomic,assign)NSInteger columnCount;// 列数property(nonatomic,assign)CGFloat columnSpacing;// 列间距property(nonatomic,assign)CGFloat rowSpacing;// 行间距property(nonatomic,assign)UIEdgeInsets sectionInset;// 内边距end#importWaterfallLayout.hinterfaceWaterfallLayout()// 存储所有cell的布局属性property(nonatomic,strong)NSMutableArray*attrsArray;// 记录每一列当前的总高度property(nonatomic,strong)NSMutableArray*columnHeightArray;endimplementationWaterfallLayout-(instancetype)init{if(self[superinit]){// 默认参数_columnCount2;_columnSpacing10;_rowSpacing10;_sectionInsetUIEdgeInsetsZero;}returnself;}#pragmamark-布局核心重写方法// 1. 准备布局-(void)prepareLayout{[superprepareLayout];// 清空旧数据[self.attrsArray removeAllObjects];[self.columnHeightArray removeAllObjects];// 初始化每一列的高度 顶部内边距for(inti0;iself.columnCount;i){[self.columnHeightArray addObject:(self.sectionInset.top)];}NSInteger itemCount[self.collectionView numberOfItemsInSection:0];// 遍历所有cell计算位置for(inti0;iitemCount;i){NSIndexPath*indexPath[NSIndexPath indexPathForItem:i inSection:0];UICollectionViewLayoutAttributes*attrs[selflayoutAttributesForItemAtIndexPath:indexPath];[self.attrsArray addObject:attrs];}}// 2. 返回所有cell的布局属性-(NSArrayUICollectionViewLayoutAttributes**)layoutAttributesForElementsInRect:(CGRect)rect{returnself.attrsArray;}// 3. 计算单个cell的frame-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath{UICollectionViewLayoutAttributes*attrs[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];// 1. 计算cell宽度CGFloat totalWself.collectionView.bounds.size.width;CGFloat cellW(totalW-self.sectionInset.left-self.sectionInset.right-(self.columnCount-1)*self.columnSpacing)/self.columnCount;// 2. 找出当前高度最短的列NSInteger minColumn0;CGFloat minHeight[self.columnHeightArray[0]floatValue];for(inti1;iself.columnCount;i){CGFloat h[self.columnHeightArray[i]floatValue];if(hminHeight){minHeighth;minColumni;}}// 3. 获取cell高度代理回调CGFloat cellH[self.delegate waterfallLayout:selfheightForItemAtIndexPath:indexPath];// 4. 计算x、yCGFloat cellXself.sectionInset.leftminColumn*(cellWself.columnSpacing);CGFloat cellYminHeight;// 5. 赋值frameattrs.frameCGRectMake(cellX,cellY,cellW,cellH);// 6. 更新当前列的总高度叠加行间距self.columnHeightArray[minColumn](cellYcellHself.rowSpacing);returnattrs;}// 4. 返回collectionView整体内容高度-(CGSize)collectionViewContentSize{// 找出最高的列高度CGFloat maxH0;for(NSNumber*hinself.columnHeightArray){if(h.floatValuemaxH){maxHh.floatValue;}}returnCGSizeMake(self.collectionView.bounds.size.width,maxH);}#pragmamark-懒加载-(NSMutableArray*)attrsArray{if(!_attrsArray){_attrsArray[NSMutableArray array];}return_attrsArray;}-(NSMutableArray*)columnHeightArray{if(!_columnHeightArray){_columnHeightArray[NSMutableArray array];}return_columnHeightArray;}end五、属性与方法// cell 大小layout.itemSizeCGSizeMake(100,120);// 横向间距layout.minimumInteritemSpacing10;// 纵向间距layout.minimumLineSpacing15;// 内边距layout.sectionInsetUIEdgeInsetsMake(20,20,20,20);// 滚动方向layout.scrollDirectionUICollectionViewScrollDirectionVertical;// 垂直layout.scrollDirectionUICollectionViewScrollDirectionHorizontal;// 水平// 多少组-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView{return2;}// 每组数据不同-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{if(section0)return6;return8;}// 注册头部[self.collectionView registerClass:[UICollectionReusableView class]forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderID];// 返回头部视图-(UICollectionReusableView*)collectionView:(UICollectionView*)collectionView viewForSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath{if(kindUICollectionElementKindSectionHeader){UICollectionReusableView*header[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderIDforIndexPath:indexPath];header.backgroundColor[UIColor redColor];returnheader;}returnnil;}// 头部高度-(CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{returnCGSizeMake(self.view.bounds.size.width,50);}layout.scrollDirectionUICollectionViewScrollDirectionHorizontal;
UICollectionView基础
UICollectionView基础文章目录UICollectionView基础一、它到底是什么1. 核心三要素2. 必须遵守的协议3. 核心机制复用池二、第一步创建自定义 Cell三、第二步ViewController 完整代码四、自定义Layout实现瀑布流五、属性与方法一、它到底是什么1. 核心三要素UICollectionView展示在屏幕上的列表容器能滚动、放很多 cellUICollectionViewCell列表里每一个格子 / 卡片UICollectionViewLayout布局规则决定 cell 多大、怎么排、间距多少2. 必须遵守的协议UICollectionViewDataSource提供数据多少个、显示什么UICollectionViewDelegateFlowLayout控制布局、点击事件3. 核心机制复用池屏幕只显示 10 个 cell滑出屏幕的 cell → 放进复用池新进入屏幕的 cell → 从复用池取二、第一步创建自定义 Cell#importUIKit/UIKit.hinterfaceMyCollectionViewCell:UICollectionViewCell// 暴露给外面用的控件property(nonatomic,strong)UILabel*titleLabel;property(nonatomic,strong)UIImageView*iconImageView;end#importMyCollectionViewCell.himplementationMyCollectionViewCell// 初始化 Cell-(instancetype)initWithFrame:(CGRect)frame{self[superinitWithFrame:frame];if(self){// 背景self.backgroundColor[UIColor whiteColor];self.layer.cornerRadius8;self.layer.masksToBoundsYES;// 图片_iconImageView[[UIImageView alloc]initWithFrame:CGRectMake(10,10,60,60)];_iconImageView.backgroundColor[UIColor lightGrayColor];_iconImageView.contentModeUIViewContentModeScaleAspectFill;_iconImageView.clipsToBoundsYES;[self.contentView addSubview:_iconImageView];// 文字_titleLabel[[UILabel alloc]initWithFrame:CGRectMake(10,80,80,20)];_titleLabel.font[UIFont systemFontOfSize:14];_titleLabel.textAlignmentNSTextAlignmentCenter;[self.contentView addSubview:_titleLabel];}returnself;}end三、第二步ViewController 完整代码#importUIKit/UIKit.hinterfaceViewController:UIViewControllerend#importViewController.h#importMyCollectionViewCell.h// 1. 遵守协议interfaceViewController()UICollectionViewDataSource,UICollectionViewDelegateFlowLayoutproperty(nonatomic,strong)UICollectionView*collectionView;property(nonatomic,strong)NSArray*dataArray;// 数据endimplementationViewController-(void)viewDidLoad{[superviewDidLoad];self.view.backgroundColor[UIColor whiteColor];// 模拟数据self.dataArray[苹果,香蕉,西瓜,橙子,葡萄,梨子,桃子,菠萝,草莓,芒果,榴莲,火龙果];// 2. 创建布局 LayoutUICollectionViewFlowLayout*layout[[UICollectionViewFlowLayout alloc]init];// 滚动方向垂直/水平layout.scrollDirectionUICollectionViewScrollDirectionVertical;// cell 大小layout.itemSizeCGSizeMake(100,120);// 横向间距cell 与 cell 左右layout.minimumInteritemSpacing10;// 纵向间距行与行之间layout.minimumLineSpacing15;// 整个列表的内边距上、左、下、右layout.sectionInsetUIEdgeInsetsMake(20,20,20,20);// 3. 创建 CollectionViewself.collectionView[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];self.collectionView.backgroundColor[UIColor groupTableViewBackgroundColor];// 设置数据源和代理self.collectionView.dataSourceself;self.collectionView.delegateself;[self.view addSubview:self.collectionView];// 4. 注册自定义 Cell必须[self.collectionView registerClass:[MyCollectionViewCell class]forCellWithReuseIdentifier:MyCellID];}#pragmamark-必须实现的数据源方法// 每组多少个 cell-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{returnself.dataArray.count;}// 生成/复用 cell-(UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath{// 从复用池取 cell核心MyCollectionViewCell*cell[collectionView dequeueReusableCellWithReuseIdentifier:MyCellIDforIndexPath:indexPath];// 给 cell 赋值NSString*textself.dataArray[indexPath.item];cell.titleLabel.texttext;// 随机颜色cell.backgroundColor[UIColor colorWithHue:arc4random()%256/255.0saturation:0.5brightness:0.9alpha:1];returncell;}#pragmamark-常用代理方法// 点击 cell-(void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath{// 取消选中高亮[collectionView deselectItemAtIndexPath:indexPath animated:YES];NSLog(点击了%,self.dataArray[indexPath.item]);}// 每个 cell 自定义大小-(CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath{returnCGSizeMake(100,120);}end四、自定义Layout实现瀑布流#importUIKit/UIKit.hclassWaterfallLayout;protocolWaterfallLayoutDelegateNSObject// 代理返回每个cell的高度-(CGFloat)waterfallLayout:(WaterfallLayout*)layout heightForItemAtIndexPath:(NSIndexPath*)indexPath;endinterfaceWaterfallLayout:UICollectionViewLayoutproperty(nonatomic,weak)idWaterfallLayoutDelegatedelegate;property(nonatomic,assign)NSInteger columnCount;// 列数property(nonatomic,assign)CGFloat columnSpacing;// 列间距property(nonatomic,assign)CGFloat rowSpacing;// 行间距property(nonatomic,assign)UIEdgeInsets sectionInset;// 内边距end#importWaterfallLayout.hinterfaceWaterfallLayout()// 存储所有cell的布局属性property(nonatomic,strong)NSMutableArray*attrsArray;// 记录每一列当前的总高度property(nonatomic,strong)NSMutableArray*columnHeightArray;endimplementationWaterfallLayout-(instancetype)init{if(self[superinit]){// 默认参数_columnCount2;_columnSpacing10;_rowSpacing10;_sectionInsetUIEdgeInsetsZero;}returnself;}#pragmamark-布局核心重写方法// 1. 准备布局-(void)prepareLayout{[superprepareLayout];// 清空旧数据[self.attrsArray removeAllObjects];[self.columnHeightArray removeAllObjects];// 初始化每一列的高度 顶部内边距for(inti0;iself.columnCount;i){[self.columnHeightArray addObject:(self.sectionInset.top)];}NSInteger itemCount[self.collectionView numberOfItemsInSection:0];// 遍历所有cell计算位置for(inti0;iitemCount;i){NSIndexPath*indexPath[NSIndexPath indexPathForItem:i inSection:0];UICollectionViewLayoutAttributes*attrs[selflayoutAttributesForItemAtIndexPath:indexPath];[self.attrsArray addObject:attrs];}}// 2. 返回所有cell的布局属性-(NSArrayUICollectionViewLayoutAttributes**)layoutAttributesForElementsInRect:(CGRect)rect{returnself.attrsArray;}// 3. 计算单个cell的frame-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath{UICollectionViewLayoutAttributes*attrs[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];// 1. 计算cell宽度CGFloat totalWself.collectionView.bounds.size.width;CGFloat cellW(totalW-self.sectionInset.left-self.sectionInset.right-(self.columnCount-1)*self.columnSpacing)/self.columnCount;// 2. 找出当前高度最短的列NSInteger minColumn0;CGFloat minHeight[self.columnHeightArray[0]floatValue];for(inti1;iself.columnCount;i){CGFloat h[self.columnHeightArray[i]floatValue];if(hminHeight){minHeighth;minColumni;}}// 3. 获取cell高度代理回调CGFloat cellH[self.delegate waterfallLayout:selfheightForItemAtIndexPath:indexPath];// 4. 计算x、yCGFloat cellXself.sectionInset.leftminColumn*(cellWself.columnSpacing);CGFloat cellYminHeight;// 5. 赋值frameattrs.frameCGRectMake(cellX,cellY,cellW,cellH);// 6. 更新当前列的总高度叠加行间距self.columnHeightArray[minColumn](cellYcellHself.rowSpacing);returnattrs;}// 4. 返回collectionView整体内容高度-(CGSize)collectionViewContentSize{// 找出最高的列高度CGFloat maxH0;for(NSNumber*hinself.columnHeightArray){if(h.floatValuemaxH){maxHh.floatValue;}}returnCGSizeMake(self.collectionView.bounds.size.width,maxH);}#pragmamark-懒加载-(NSMutableArray*)attrsArray{if(!_attrsArray){_attrsArray[NSMutableArray array];}return_attrsArray;}-(NSMutableArray*)columnHeightArray{if(!_columnHeightArray){_columnHeightArray[NSMutableArray array];}return_columnHeightArray;}end五、属性与方法// cell 大小layout.itemSizeCGSizeMake(100,120);// 横向间距layout.minimumInteritemSpacing10;// 纵向间距layout.minimumLineSpacing15;// 内边距layout.sectionInsetUIEdgeInsetsMake(20,20,20,20);// 滚动方向layout.scrollDirectionUICollectionViewScrollDirectionVertical;// 垂直layout.scrollDirectionUICollectionViewScrollDirectionHorizontal;// 水平// 多少组-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView{return2;}// 每组数据不同-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{if(section0)return6;return8;}// 注册头部[self.collectionView registerClass:[UICollectionReusableView class]forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderID];// 返回头部视图-(UICollectionReusableView*)collectionView:(UICollectionView*)collectionView viewForSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath{if(kindUICollectionElementKindSectionHeader){UICollectionReusableView*header[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:HeaderIDforIndexPath:indexPath];header.backgroundColor[UIColor redColor];returnheader;}returnnil;}// 头部高度-(CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{returnCGSizeMake(self.view.bounds.size.width,50);}layout.scrollDirectionUICollectionViewScrollDirectionHorizontal;