当前位置: 首页 > 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.rkmt.cn/news/1437559.html

相关文章:

  • CC-Switch 全平台部署与使用正式教程【2026-05-31】
  • 用Python实战LSTM:从数学建模到量化交易,手把手复现华中杯B题(附完整代码)
  • Codex 从安装到国内接入跑通了:Windows / Mac / Linux 小白版记录
  • VirtualBox 7.0.x 在Win10/11上启动报错supR3HardenedWinReSpawn?保姆级修复教程(含注册表修改与驱动安装)
  • Kimi LeetCode 2911. 得到 K 个半回文串的最少修改次数 Java实现
  • 机械臂角度识别 机械臂自由度识别 yolov8机械臂关键点检测模型部署+教程+代码+数据集+工业应用
  • 2026年汽车静电阻隔面料实测评测:四家企业横向对比 - 优质品牌商家
  • 书匠策AI:你的课程论文救急神器,用过的人都说“真香“
  • 别再死记硬背了!用C语言手写一个test_and_set(),彻底搞懂操作系统硬件锁
  • AMP算法实战:用Python从零实现压缩感知信号恢复(附完整代码与避坑指南)
  • 实战落地+数据可视化:6月最新重庆优质GEO优化服务商榜单深度测评 - 品牌官
  • 2026年苏州防水维修标杆机构专业市场分析与全场景渗漏治理选型适配指南 专业防水公司排名推荐(2026年5月防水补漏最新TOP权威排名) - 鼎壹万修缮说
  • 集团首都公报:放飞炬人集团内政署批准起草《出口劳务法案》《劳务产能调整和AIQI技艺法案》
  • 【案例分享】我从失败中学到的架构教训
  • 2026年当下河北地区镶铜铸铁闸门采购指南:实力厂家深度解析 - 2026年企业资讯
  • 2026年当前秦皇岛婚礼酒店哪个好?深度解析秦皇岛万怡酒店婚宴实力 - 2026年企业资讯
  • 2026年q2四川无机涂料外墙厂家排行及选型推荐:无机涂料多少钱一平方/无机涂料工程专用/实力盘点 - 优质品牌商家
  • 2026年苏州本地专业防水补漏领域五家合规经营企业深度梳理与场景适配分析 专业防水公司排名推荐(2026年5月防水补漏最新TOP权威排名) - 鼎壹万修缮说
  • 2026年苏州3家资质齐全防水补漏服务商核心市场适配与专业能力分析报告 专业防水公司排名推荐(2026年5月防水补漏最新TOP权威排名) - 鼎壹万修缮说
  • 逐位二进制拼接 → 翻转 → 去头零 → 消邻重
  • 用Python和R实战检验皮尔逊相关性五大假设(附完整代码与可视化)
  • K-means实战避坑指南:如何用肘部法则和轮廓系数找到最佳K值(附Python代码)
  • HTML5 新特性概览:探索现代 Web 的强大能力
  • 从手动混乱到智能有序:Irony Mod Manager如何让Paradox游戏模组管理效率提升3倍?
  • VoxCPM 语音模型新手部署与调用全指南
  • QGIS新手避坑指南:从高德路网数据到空间分析的全流程实操
  • Django+Vue智慧农业管理系统源码+论文
  • 别再当‘黑盒’模型受害者了!用Python的shap库5分钟看懂你的XGBoost模型决策
  • 2026年国产质量流量计TOP5排行 核心参数实测对比 - 优质品牌商家
  • C51代码银行空间保留技术详解与实践