当前位置: 首页 > news >正文

UICollectionView基础

UICollectionView基础

文章目录

  • UICollectionView基础
    • 一、它到底是什么?
      • 1. 核心三要素
      • 2. 必须遵守的协议
      • 3. 核心机制:复用池
    • 二、第一步:创建自定义 Cell
    • 三、第二步:ViewController 完整代码
    • 四、自定义Layout实现瀑布流
    • 五、属性与方法

一、它到底是什么?

1. 核心三要素

  • UICollectionView:展示在屏幕上的列表容器(能滚动、放很多 cell)
  • UICollectionViewCell:列表里每一个格子 / 卡片
  • UICollectionViewLayout布局规则(决定 cell 多大、怎么排、间距多少)

2. 必须遵守的协议

  • UICollectionViewDataSource:提供数据(多少个、显示什么)
  • UICollectionViewDelegateFlowLayout:控制布局、点击事件

3. 核心机制:复用池

  • 屏幕只显示 10 个 cell
  • 滑出屏幕的 cell → 放进复用池
  • 新进入屏幕的 cell → 从复用池取

二、第一步:创建自定义 Cell

#import<UIKit/UIKit.h>@interfaceMyCollectionViewCell:UICollectionViewCell// 暴露给外面用的控件@property(nonatomic,strong)UILabel*titleLabel;@property(nonatomic,strong)UIImageView*iconImageView;@end
#import"MyCollectionViewCell.h"@implementationMyCollectionViewCell// 初始化 Cell-(instancetype)initWithFrame:(CGRect)frame{self=[superinitWithFrame:frame];if(self){// 背景self.backgroundColor=[UIColor whiteColor];self.layer.cornerRadius=8;self.layer.masksToBounds=YES;// 图片_iconImageView=[[UIImageView alloc]initWithFrame:CGRectMake(10,10,60,60)];_iconImageView.backgroundColor=[UIColor lightGrayColor];_iconImageView.contentMode=UIViewContentModeScaleAspectFill;_iconImageView.clipsToBounds=YES;[self.contentView addSubview:_iconImageView];// 文字_titleLabel=[[UILabel alloc]initWithFrame:CGRectMake(10,80,80,20)];_titleLabel.font=[UIFont systemFontOfSize:14];_titleLabel.textAlignment=NSTextAlignmentCenter;[self.contentView addSubview:_titleLabel];}returnself;}@end

三、第二步:ViewController 完整代码

#import<UIKit/UIKit.h>@interfaceViewController:UIViewController@end
#import"ViewController.h"#import"MyCollectionViewCell.h"// 1. 遵守协议@interfaceViewController()<UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>@property(nonatomic,strong)UICollectionView*collectionView;@property(nonatomic,strong)NSArray*dataArray;// 数据@end@implementationViewController-(void)viewDidLoad{[superviewDidLoad];self.view.backgroundColor=[UIColor whiteColor];// 模拟数据self.dataArray=@[@"苹果",@"香蕉",@"西瓜",@"橙子",@"葡萄",@"梨子",@"桃子",@"菠萝",@"草莓",@"芒果",@"榴莲",@"火龙果"];// 2. 创建布局 LayoutUICollectionViewFlowLayout*layout=[[UICollectionViewFlowLayout alloc]init];// 滚动方向:垂直/水平layout.scrollDirection=UICollectionViewScrollDirectionVertical;// cell 大小layout.itemSize=CGSizeMake(100,120);// 横向间距(cell 与 cell 左右)layout.minimumInteritemSpacing=10;// 纵向间距(行与行之间)layout.minimumLineSpacing=15;// 整个列表的内边距(上、左、下、右)layout.sectionInset=UIEdgeInsetsMake(20,20,20,20);// 3. 创建 CollectionViewself.collectionView=[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];self.collectionView.backgroundColor=[UIColor groupTableViewBackgroundColor];// 设置数据源和代理self.collectionView.dataSource=self;self.collectionView.delegate=self;[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:@"MyCellID"forIndexPath:indexPath];// 给 cell 赋值NSString*text=self.dataArray[indexPath.item];cell.titleLabel.text=text;// 随机颜色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实现瀑布流

#import<UIKit/UIKit.h>@classWaterfallLayout;@protocolWaterfallLayoutDelegate<NSObject>// 代理:返回每个cell的高度-(CGFloat)waterfallLayout:(WaterfallLayout*)layout heightForItemAtIndexPath:(NSIndexPath*)indexPath;@end@interfaceWaterfallLayout:UICollectionViewLayout@property(nonatomic,weak)id<WaterfallLayoutDelegate>delegate;@property(nonatomic,assign)NSInteger columnCount;// 列数@property(nonatomic,assign)CGFloat columnSpacing;// 列间距@property(nonatomic,assign)CGFloat rowSpacing;// 行间距@property(nonatomic,assign)UIEdgeInsets sectionInset;// 内边距@end
#import"WaterfallLayout.h"@interfaceWaterfallLayout()// 存储所有cell的布局属性@property(nonatomic,strong)NSMutableArray*attrsArray;// 记录每一列当前的总高度@property(nonatomic,strong)NSMutableArray*columnHeightArray;@end@implementationWaterfallLayout-(instancetype)init{if(self=[superinit]){// 默认参数_columnCount=2;_columnSpacing=10;_rowSpacing=10;_sectionInset=UIEdgeInsetsZero;}returnself;}#pragmamark-布局核心重写方法// 1. 准备布局-(void)prepareLayout{[superprepareLayout];// 清空旧数据[self.attrsArray removeAllObjects];[self.columnHeightArray removeAllObjects];// 初始化每一列的高度 = 顶部内边距for(inti=0;i<self.columnCount;i++){[self.columnHeightArray addObject:@(self.sectionInset.top)];}NSInteger itemCount=[self.collectionView numberOfItemsInSection:0];// 遍历所有cell,计算位置for(inti=0;i<itemCount;i++){NSIndexPath*indexPath=[NSIndexPath indexPathForItem:i inSection:0];UICollectionViewLayoutAttributes*attrs=[selflayoutAttributesForItemAtIndexPath:indexPath];[self.attrsArray addObject:attrs];}}// 2. 返回所有cell的布局属性-(NSArray<UICollectionViewLayoutAttributes*>*)layoutAttributesForElementsInRect:(CGRect)rect{returnself.attrsArray;}// 3. 计算单个cell的frame-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath{UICollectionViewLayoutAttributes*attrs=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];// 1. 计算cell宽度CGFloat totalW=self.collectionView.bounds.size.width;CGFloat cellW=(totalW-self.sectionInset.left-self.sectionInset.right-(self.columnCount-1)*self.columnSpacing)/self.columnCount;// 2. 找出当前高度最短的列NSInteger minColumn=0;CGFloat minHeight=[self.columnHeightArray[0]floatValue];for(inti=1;i<self.columnCount;i++){CGFloat h=[self.columnHeightArray[i]floatValue];if(h<minHeight){minHeight=h;minColumn=i;}}// 3. 获取cell高度(代理回调)CGFloat cellH=[self.delegate waterfallLayout:selfheightForItemAtIndexPath:indexPath];// 4. 计算x、yCGFloat cellX=self.sectionInset.left+minColumn*(cellW+self.columnSpacing);CGFloat cellY=minHeight;// 5. 赋值frameattrs.frame=CGRectMake(cellX,cellY,cellW,cellH);// 6. 更新当前列的总高度(叠加行间距)self.columnHeightArray[minColumn]=@(cellY+cellH+self.rowSpacing);returnattrs;}// 4. 返回collectionView整体内容高度-(CGSize)collectionViewContentSize{// 找出最高的列高度CGFloat maxH=0;for(NSNumber*hinself.columnHeightArray){if(h.floatValue>maxH){maxH=h.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.itemSize=CGSizeMake(100,120);// 横向间距layout.minimumInteritemSpacing=10;// 纵向间距layout.minimumLineSpacing=15;// 内边距layout.sectionInset=UIEdgeInsetsMake(20,20,20,20);// 滚动方向layout.scrollDirection=UICollectionViewScrollDirectionVertical;// 垂直layout.scrollDirection=UICollectionViewScrollDirectionHorizontal;// 水平
// 多少组-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView{return2;}// 每组数据不同-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section{if(section==0)return6;return8;}
// 注册头部[self.collectionView registerClass:[UICollectionReusableView class]forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderID"];// 返回头部视图-(UICollectionReusableView*)collectionView:(UICollectionView*)collectionView viewForSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath{if(kind==UICollectionElementKindSectionHeader){UICollectionReusableView*header=[collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderID"forIndexPath: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.scrollDirection=UICollectionViewScrollDirectionHorizontal;
http://www.jsqmd.com/news/926227/

相关文章:

  • 国内的七大主流大模型推荐算法有那些差异
  • CC-Switch 全平台部署与使用正式教程【2026-05-31】
  • AI时代艺术家的反抗
  • 【AI问答】GoLang关于代码复用
  • 基于 Isolation Forest + PyOD + Streamlit 的工业设备异常检测与故障预警系统:Python 机器学习项目实战
  • 用Python实战LSTM:从数学建模到量化交易,手把手复现华中杯B题(附完整代码)
  • 2026年苏州本地正规房屋漏水维修三家机构核心能力梳理与场景适配分析 专业防水公司排名推荐(2026年6月防水补漏最新TOP权威排名) - 鼎壹万修缮说
  • Gemini Agent框架实战:从零搭建可商用自动化工作流,含3套已通过SOC2认证的Prompt架构
  • 避开SHL题库陷阱:手把手教你高效准备联想技术岗笔试(附图形推理真题思路)
  • Codex 从安装到国内接入跑通了:Windows / Mac / Linux 小白版记录
  • PYTHON+AI LLM DAY SIXTY-TWO
  • HPC基准测试:核心价值、分类法与优化实践
  • Keil MDK调试中System Viewer外设寄存器缺失问题解决方案
  • 2026年5月更新:深度剖析四川仟屹集团AI今日头条可靠服务商选择之道 - 2026年企业资讯
  • 书匠策AI:我劝你别再熬夜肝课程论文了,这个工具真的能救命
  • 方达炬:方家 将用5到10年时间建设【高福利家庭】
  • VirtualBox 7.0.x 在Win10/11上启动报错supR3HardenedWinReSpawn?保姆级修复教程(含注册表修改与驱动安装)
  • 从SVD到RANSAC:深入理解点云平面拟合的数学原理与Python实现细节
  • 20260531 区块链与数字货币 实验二:图算法与社交网络分析
  • 2026优质玻璃纤维制造商标杆名录:玻璃纤维销售厂家、玻璃纤维企业、玻璃纤维优质厂家、玻璃纤维供应厂家、玻璃纤维供货商选择指南 - 优质品牌商家
  • 【稳定性评测】同样的 Prompt 测试十次结果都不一样?如何通过系统提示控制一致性
  • `build-your-own-x` 涨了817星,但今天真正该装的是这个
  • web 第二次作业
  • MiMo Vision Router:让纯文本模型秒变多模态
  • 我写了十年代码,直到AI出现
  • 【Android】手机屏幕劫持防护
  • Keil C51编译器Makefile选项解析与替代方案
  • Kimi LeetCode 2911. 得到 K 个半回文串的最少修改次数 Java实现
  • 机械臂角度识别 机械臂自由度识别 yolov8机械臂关键点检测模型部署+教程+代码+数据集+工业应用
  • 量子计算冗余架构:双星设计提升容错与并行能力