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

【iOS】UICollectionView

【iOS】UICollectionView

  • 前言
  • 基础使用
  • 常用方法和属性
    • UICollectionViewFlowLayout属性
    • UICollectionView属性
    • 协议代理方法
      • UICollectionViewDelegate
      • UICollectionViewDataSource
      • UICollectionViewDelegateFlowLayout
  • 实现瀑布流
    • 实现原理
    • 实现步骤
    • 调用顺序
    • 实现效果
  • 总结

前言

UICollectionView是iOS26之后UIKit框架中引入的一个新的控件,用于实现网格布局、横向滚动列表、照片墙、轮播图等复杂布局的强大控件。

相比UITableView:

  • 不再只能垂直滚动,其滚动方向可垂直、水平或自定义。
  • 通过UICollectionViewLayout控制进行布局。
  • 通过layout布局回调的代理方法可以动态地定制每个item的大小和collection的布局属性。
  • UICollectionView中Item的大小位置可自定义。
  • 更加灵活。

基础使用

我们先实现一个简单的九宫格布局:

  • 创建布局类并为其各个属性赋值
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
//设置布局方向为垂直流分布
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
//行间距
layout.minimumLineSpacing = 50;
//列间距
layout.minimumInteritemSpacing = 10;
//设置每个item的大小
layout.itemSize = CGSizeMake(100, 100);
  • 将自定义的布局类作为参数传递给UICollectionView的初始化
UICollectionView *collect = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
  • 设置代理
collect.delegate = self;
collect.dataSource = self;
  • 注册item类型
[collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
  • 实现协议函数

与tableView类似。

-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];//arc4random():C语言标准库函数,随机生成数//arc4random() % 255 / 255.0:使得随机生成在0-1之间,避免特别大的数cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];return cell;
}-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {return 9;
}

对比一下collectionView和tableView在复用cell时的区别:

  • UITableViewCell:
    • 旧式方法:如果复用池中没有cell,可以返回nil,再临时创建即可。
    - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
    }
    
    • 新式方法:必须提前注册过cell。如果没有注册,系统会直接崩溃。
    - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath
    
  • UICollectionView:
    因为UICollectionView没有默认的cell类型,所以所有的cell都必须由开发者自定义并提前注册
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];return cell;
}

这样我们就实现了这个九宫格:
在这里插入图片描述

常用方法和属性

UICollectionViewFlowLayout属性

查看一下API,按照系统给我们的可以设置的属性依次有行间距、列间距、每个item的大小、预估大小、滚动方向、每个section头视图的尺寸、每个section尾视图的尺寸、每个section的内边距、sectionInset 的参考边界、header是否悬停、footer是否吸底。

在这里插入图片描述

其中常用的有:

  • 布局类方向
    • 垂直排布
    layout.scrollDirection = UICollectionViewScrollDirectionVertical;
    
    • 水平排布
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    
  • 设置item
//item大小
layout.itemSize = CGSizeMake(100, 100);
//item行间距
layout.minimumLineSpacing = 50;
//item列间距
layout.minimumInteritemSpacing = 10;
  • section的内边距
layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);

每个参数分别对应:

在这里插入图片描述

UICollectionView属性

  • 刷新对应列
[collect performBatchUpdates:^{[collect reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];

协议代理方法

UICollectionViewDelegate

该协议中所有方法都是可选实现。

  • 是否允许某个item被高亮,按下item后,系统准备高亮显示前调用,默认YES会进入高亮状态(按下前)
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
  • 按下item后立即调用,此时手指还未松开(按下后)
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
  • 手指离开item区域(松开后)
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
  • 是否允许选中某个item,在item被选中前调用,默认YES允许选中(选中前)
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
  • 是否允许取消选中,当再次点击已选中的item,系统准备取消选中时调用,默认YES允许取消选中(取消选中前)
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; 

注意:该方法必须在允许多选时才可调用

collect.allowsMultipleSelection = YES;
  • 通知某个item已被选中,点击item后松手时调用,即真正选中时(选中后)
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
  • 通知某个item已被取消选中,当取消选中某个item时调用(取消选中后)
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

UICollectionViewDataSource

查看一下API:

在这里插入图片描述

我们可以很清楚地看到以下两个方法是必须实现的:

  • 设置每个section的item数量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
  • 返回对应位置的cell对象
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

可选实现的:

  • 设置section数量,默认有1个section
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
  • 对头视图或尾视图进行设置
//UICollectionElementKindSectionHeader头视图
//UICollectionElementKindSectionFooter尾视图
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
  • 某个item是否可以被移动,默认返回NO
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(9.0));
  • 移动item时调用,只能在上述方法返回YES时调用
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath API_AVAILABLE(ios(9.0));

UICollectionViewDelegateFlowLayout

有时我们想让每个item展现不同,我们可以通过该协议方法设置。

在这里插入图片描述

根据API中方法依次可以设置每个item大小、每个section的内边距、行间距、列间距、头视图大小、尾视图大小。

实现瀑布流

实现原理

首先,我们要知道UICollectionView的布局过程实际上是调用UICollectionViewLayout的一些函数,这些函数的执行是依据一定顺序的。

在这里插入图片描述

简单来说,UICollectionView的布局是由UICollectionViewLayout的子类控制的。

因此,为了实现我们的自动移瀑布流,我们需要在其子类中重写生成布局的方法,创建我们自己需要的布局。

按照顺序实现以下方法:

  • 布局准备阶段调用
-(void)prepareLayout;
  • 设置collectionView内容区域总大小
-(CGSize)collectionViewContentSize;
  • 返回rect中所有元素的布局属性,返回一个数组
-(NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
  • 返回对应indexPath位置的item的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
  • 返回区域头或区域尾的布局属性
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
  • 返回装饰视图的布局属性
- (nullable UICollectionViewLayoutAttributes )layoutAttributesForDecorationViewOfKind:(NSString)elementKind atIndexPath:(NSIndexPath *)indexPath;
  • 当边界发生改变时,是否刷新
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

实现步骤

  • -(void)prepareLayout

该方法在布局发生变化之前调用,比如初始化、调用reloadData、invalidateLayout(重新计算item位置和尺寸)等方法。用来进行布局前的准备,其主要作用有:

  1. 初始化布局参数:进行初始化工作,如计算和缓存用于布局的参数,可能包括计算每个单元格的大小、计算行列的数量、初始化用于存储布局属性的数据结构等。
  2. 计算并布局属性:计算并缓存集合视图中所有单元格的布局属性(UICollectionViewLayoutAttributes)。这样使得集合视图需要显示或进行交互时,可以直接访问缓存的布局属性,而不需要在运行时动态计算。
-(instancetype)init {if (self = [super init]) {self.columnCount = 2;self.columnMargin = 10;self.rowMargin = 10;self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);}return self;
}-(void)prepareLayout {[super prepareLayout];self.attributeArray = [NSMutableArray array];self.columnHeights = [NSMutableArray array];for (int i = 0; i < self.columnCount; i++) {[self.columnHeights addObject:@(self.sectionInset.top)];}//寻找最短列,保证下一个item放在当前最短列下面,使得整体布局符合瀑布流自然排列NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];for (int i = 0; i < itemCount; i++) {NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];CGFloat minColumnHeight = [self.columnHeights[0] floatValue];NSInteger minColumnIndex = 0;for (int j = 1; j < self.columnCount; j++) {CGFloat columnHeight = [self.columnHeights[j] floatValue];if (columnHeight < minColumnHeight) {minColumnHeight = columnHeight;minColumnIndex = j;}}CGFloat itemWidth = (CGRectGetWidth(self.collectionView.bounds) - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;CGFloat itemHeight = arc4random_uniform(100) + 100;CGFloat itemX = self.sectionInset.left + minColumnIndex * (itemWidth + self.columnMargin);CGFloat itemY = minColumnHeight;UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);[self.attributeArray addObject:attributes];//每次更新那一列的最新底部高度//CGRectGetMaxY的计算 = y + heightself.columnHeights[minColumnIndex] = @(CGRectGetMaxY(attributes.frame) + self.rowMargin);}
}

我们通过API看一下我们可以设置哪些布局类对象的属性:
在这里插入图片描述

  • -(CGSize)collectionViewContentSize

该方法在需要计算集合视图内容尺寸时调用,比如初始化时、布局发生变化时等。决定了集合视图可以滚动的范围,即集合视图可以在其内容区域内滚动的最大范围,返回整个集合视图内容的尺寸。

-(CGSize)collectionViewContentSize {CGFloat maxColumnHeight = [self.columnHeights[0] floatValue];for (int i = 1; i < self.columnCount; i++) {maxColumnHeight = MAX(maxColumnHeight, [self.columnHeights[i] floatValue]);}return CGSizeMake(self.collectionView.bounds.size.width, maxColumnHeight);
}
  • -(NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect

在需要显示或更新某个区域内视图时调用,比如滚动、布局发生变化时。传入一个rect参数,返回在给定rect区域内的所有视图的布局属性数组。

-(NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {return self.attributeArray;
}
  • 调用-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath,创建item,配置单元格。
-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {NSLog(@"-(__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath");UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];//arc4random():C语言标准库函数,随机生成数//arc4random() % 255 / 255.0:使得随机生成在0-1之间,避免特别大的数cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];return cell;
}

调用顺序

我们使用NSLog打印出来每个函数,可以直观的看出:-(void)prepareLayout方法只调用一次,之后会在往下滑动UICollectionView时不断重复调用其他方法。

在这里插入图片描述

实现效果

在这里插入图片描述

总结

相较于仅能纵向单列数据展示的tableView,collectionView允许我们进行更加自由灵活的布局。而自定义UICollectionViewFlowLayout类,且重写该类中方法可以实现我们单元格的多样布局。

http://www.dtcms.com/a/572805.html

相关文章:

  • 广东电白建设集团有限公司网站宫免费网站
  • 混淆 iOS 类名与变量名的实战指南,多工具组合把混淆做成工程能力(混淆 iOS 类名变量名/IPA 成品混淆Ipa/Guard CLI 实操)
  • sysstat 概览与使用:sar/iostat/mpstat/pidstat(含基础原理)
  • 纯flex布局来写瀑布流
  • 智能网联汽车与低空经济‌:结合5G技术拓展新兴产业
  • RDD的特点、算子与创建方法
  • 删除小目标 cocojson
  • 汽车EDI:基于知行之桥的 Gnotec EDI解决方案
  • 垂直行业门户网站建设方案自己做的网站被黑了怎么办
  • 地图可视化实践录:leaflet学习之综合示例工程设计
  • 《Python工匠》第二章 数值与字符串 关键知识摘录与梳理
  • QuickSSO 与 ECreator 实操应用案例手册
  • Flutter Android Kotlin 插件编译错误完整解决方案
  • 网站设计问题网站开发包含的项目和分工
  • FPGA—ZYNQ学习UART环回(五)
  • 电动汽车充电云与移动应用基础设施的漏洞识别、攻击实验及缓解策略
  • PFMEA中的预防措施和探测措施区别
  • 做钢材的网站php 7 wordpress
  • 告别繁琐手工录入:智能银行票据套打软件,让制单效率飞跃
  • 【Java】理解 Java 中的 this 关键字
  • 在编译OpenHarmony遇到third_party/libnl编译报错的修复办法
  • 建c2c网站俄罗斯乌克兰为什么打仗
  • vue在获取某一个div的大小,怎么确保div渲染好,内容撑开后才去获取大小
  • ITIL 4 复习练习及解题思路
  • 数据结构:单链表(2)
  • MYSQL数据库--索引、视图练习
  • 2.2.5 运算方法和运算电路【2011统考真题】
  • 前端上传图片加裁剪功能
  • DevEco Studio 鸿蒙 引入lib中的文件
  • 简述数据库设计--范式、ER图