小工具知识网

当前位置: 首页 > 行业知识 > 【iOS】UICollectionView使用

行业知识

【iOS】UICollectionView使用

2026-11-09 02:44:26 来源:互联网转载

使用UITableView作为表格来展示数据完全没有问题,但仍有许多局限性,对于一些更加复杂的布局样式,就有些力不从心了

比如,UITableView只允许表格每一行只能显示一个cell,而不能在一行中显示多个cell,对于这种更为复杂的布局需求,UICollectionView可以提供更好的支持,有着更大的灵活性和扩展性,其主要优势有以下几点:

  • 支持横向 + 纵向两个方向的布局
  • 更加灵活的布局方式、动画
  • 可以动态对布局进行重设(切换layout)

    目录

      • UICollectionView的基础使用
        • 显示UICollectionView
        • UICollectionViewLayout布局策略(UICollectionViewLayoutAttributes)
          • UICollectionViewFlowLayout流式布局
          • 九宫格布局
          • 更加灵活的流式布局
          • 参差瀑布流布局
            • 声明MyLayout类
            • 设置MyLayout相关属性
            • 圆环布局
            • 总结

              UICollectionView的基础使用

              作为升级版的UITableView,UICollectionView有许多与UITableView相似的点,可以通过对比UITableView总结来进行学习:

              • row —> item:由于一行可以展示多个视图,row不能准确表达
              • - (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;:注册cell类型,并设置重用ID
              • - (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;:cell复用,与UITableViewCell的注册机制一样,每次调用这个方法时,如果复用池中没有可复用的cell(cell为空),会根据重用ID自动创建一个新的cell并返回

                显示UICollectionView

                下面展示一个最基本的CollectionView:

                @interface ViewController () @end- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.        self.view.backgroundColor = [UIColor blueColor];        //创建布局策略    UICollectionViewFlowLayout* flowLayOut = [[UICollectionViewFlowLayout alloc] init];        //第二个参数flowLayout用于生成UICollectionView的布局信息,后面会解释这个布局类    UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame: self.view.bounds collectionViewLayout: flowLayOut];    collectionView.dataSource = self;        //注册cell    [collectionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier: @"UICollectionViewCell"];    [self.view addSubview: collectionView];}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return 21;}- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier: @"UICollectionViewCell" forIndexPath: indexPath];    //cell的颜色    cell.backgroundColor = [UIColor cyanColor];        //cell默认是50X50的大小        return cell;}

                UICollectionViewLayout布局策略(UICollectionViewLayoutAttributes)

                layout管理多个attributes,一个cell就会对应一个布局信息attribute

                UICollectionViewFlowLayout流式布局

                作为一个生成布局信息(item的大小、位置、3D变换等)的抽象类,要实际使用需要继承,比如系统提供的继承于UICollectionViewLayout的一个流式布局类UICollectionViewFlowLayout,下面使用这个类来进行布局:

                UICollectionViewFlowLayout* flowLayOut = [[UICollectionViewFlowLayout alloc] init];//设置布局方向flowLayOut.scrollDirection = UICollectionViewScrollDirectionVertical;flowLayOut.minimumLineSpacing = 10;  //行间距flowLayOut.minimumInteritemSpacing = 10;  //列间距//设置每个item的尺寸flowLayOut.itemSize = CGSizeMake(self.view.frame.size.width / 2 - 5, 300);//    flowLayOut.itemSize = CGSizeMake(self.view.frame.size.width / 2 - 50, 300);

                scrollDirection属性

                该类的scrollDirection属性用于设置布局的方向,支持的布局方向枚举如下:

                若将枚举值改为UICollectionViewScrollDirectionHorizontal,将会这样排列:

                前者当一行满时,另起一行;后者当一列满时,另起一列

                minimumInteritemSpacing最小列间距属性

                系统通过minimumInteritemSpacing属性计算一行可以放多少个item,当发现放不下计算好的item个数时,为了撑满所在行,此值就会变大,比如:

                flowLayOut.itemSize = CGSizeMake(self.view.frame.size.width / 2 - 12, 300);

                minimumLineSpacing最小行间距同理

                九宫格布局

                和UITableView类似,UICollectionView不仅内部也有一套复用机制来对注册的cell进行复用,而且也是通过dataSource和delegate协议来进行数据填充和相关属性设置的:

                @interface ViewController () @end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.        self.view.backgroundColor = [UIColor blueColor];        UICollectionViewFlowLayout* flowLayOut = [[UICollectionViewFlowLayout alloc] init];    flowLayOut.scrollDirection = UICollectionViewScrollDirectionVertical;        CGFloat side = (self.view.bounds.size.width - 12) / 3;    flowLayOut.minimumLineSpacing = 6;    flowLayOut.minimumInteritemSpacing = 6;    flowLayOut.itemSize = CGSizeMake(side, side);        UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame: self.view.bounds collectionViewLayout: flowLayOut];    collectionView.dataSource = self;    collectionView.delegate = self;        [collectionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier: @"UICollectionViewCell"];        [self.view addSubview: collectionView];}//设置分区数- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {    return 1;}//设置每个分区的- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return 10;}//每条item上cell的UI展现- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier: @"UICollectionViewCell" forIndexPath: indexPath];        //随机颜色    cell.backgroundColor = [UIColor colorWithRed: arc4random() % 255 / 255.0 green: arc4random() % 255 / 255.0 blue: arc4random() % 255 / 255.0 alpha: 1.0];        return cell;}
                更加灵活的流式布局
                //实现delegate,自定义任何位置上cell的样式- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {    if (indexPath.item % 2) {        return CGSizeMake((self.view.bounds.size.width - 12) / 3, (self.view.bounds.size.width - 12) / 3);    } else {        return CGSizeMake((self.view.bounds.size.width - 12) / 6, (self.view.bounds.size.width - 12) / 6);    }}

                参差瀑布流布局

                在很多应用程序中都有瀑布流效果,即分成两列或者多列进行数据的展示,每条数据item上cell的高度也随数据多少不同而显示得参差不齐

                使用系统提供的原生UICollectionViewFlowLayout类进行布局设置很难实现这样的效果,开发者可以自定义一个它的子类来实现瀑布流式的效果

                流布局又称瀑布流布局,是一种比较流行的网页布局模式,视觉效果多表现为参差不齐的多栏布局。

                声明MyLayout类

                创建一个布局类MyLayout,使其继承于UICollectionViewFlowLayout,并新增一个属性itemCount用于设置要布局的item的数量:

                MyLayout.h

                @interface MyLayout : UICollectionViewFlowLayout@property (nonatomic, assign)NSInteger itemCount;@end

                设置MyLayout相关属性

                UICollectionViewLayout类提供了prepareLayout来做布局前的准备,这个时机会调用此方法,可以在其中设置布局配置数组:

                MyLayout.m

                @implementation MyLayout {    //自定义的布局配置数组,保存每个cell的布局信息attribute    NSMutableArray* _attributeArray;}//布局前的准备会调用这个方法- (void)prepareLayout {    _attributeArray = [[NSMutableArray alloc] init];    [super prepareLayout];        //为方便演示,设置为静态的2列    //计算每一个Item的宽度    //sectionInset表示item距离section四个方向的内边距 UIEdgeInsetsMake(top, left, bottom, right)    CGFloat WIDTH = ([UIScreen mainScreen].bounds.size.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing) / 2;        //创建数组保存每一列的高度(实际是总高度),这样就可以在布局时始终将下一个Item放在最短的列下面    CGFloat colHeight[2] = {self.sectionInset.top, self.sectionInset.bottom};        //遍历每一个Item来设置布局    for (int i = 0; i  colHeight[1]) {        self.itemSize = CGSizeMake(WIDTH, (colHeight[0] - self.sectionInset.top) * 2 / self.itemCount - self.minimumLineSpacing);    } else {        self.itemSize = CGSizeMake(WIDTH, (colHeight[1] - self.sectionInset.top) * 2 / self.itemCount - self.minimumLineSpacing);    }}//此系统提供的方法会返回设置好的布局数组- (NSArray *)layoutAttributesForElementsInRect: (CGRect)rect {    return _attributeArray;}@end
                1. 先声明一个_attributeArray数组存放每个item的布局信息
                2. 在UICollectionView进行布局时,首先会调用其Layout布局类的prepareLayout方法,在这个方法中可以进行每个item布局属性的相关计算操作
                3. 具体每个item的布局属性实际是保存在UICollectionViewLayoutAttributes类对象中的,其中包括size、frame等信息,并与每个item一一对应
                4. 在prepareLayout方法准备好所有item的Attributes布局属性后,以数组的形式调用layoutAttributesForElementsInRect:方法来返回给UICollectionView进行界面的布局

                ViewController.m引入MyLayout文件并使用这个类:

                #import "MyLayout.h"- (void)viewDidLoad {    [super viewDidLoad];        self.view.backgroundColor = [UIColor blueColor];        //使用自定义的layout类    MyLayout* myLayout = [[MyLayout alloc] init];    myLayout.itemCount = 21;        UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame: self.view.bounds collectionViewLayout: myLayout];    collectionView.dataSource = self;    collectionView.delegate = self;        [self.view addSubview: collectionView];        [collectionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier: @"MyUICollectionView"];}- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {    return 1;}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return 21;}- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell* myCell = [collectionView dequeueReusableCellWithReuseIdentifier: @"MyUICollectionView" forIndexPath: indexPath];        myCell.backgroundColor = [UIColor colorWithRed: arc4random() % 255 / 255.0 green: arc4random() % 255 / 255.0 blue: arc4random() % 255 / 255.0 alpha: 1.0];        return myCell;}

                运行结果:

                圆环布局

                通过上面的代码我们可知,UICollectionView的布局原理是采用Layout类进行每个item布局信息的配置的,具体的配置信息由UICollectionViewLayoutAttributes存储

                明白了这个机制后,我们可以发挥想象实现更加炫酷复杂的布局效果

                与参差瀑布式布局一样,这里附上圆环布局代码:

                CircleLayout.h

                @interface CircleLayout : UICollectionViewFlowLayout@property (nonatomic, assign)NSInteger itemCount;@end

                CircleLayout.m

                @implementation CircleLayout {    NSMutableArray* _attributeArray;}- (void)prepareLayout {    [super prepareLayout];        //获取item的个数    self.itemCount = (int)[self.collectionView numberOfItemsInSection: 0];    _attributeArray = [[NSMutableArray alloc] init];            //先设定大圆的半径,取长和宽的最小值    CGFloat radius = MIN(self.collectionView.frame.size.width, self.collectionView.frame.size.height) / 2;    //计算圆心位置    CGPoint center = CGPointMake(self.collectionView.frame.size.width / 2, self.collectionView.frame.size.height / 2);    //每个item大小为50*50,即半径为25    for (int i = 0; i  

                ViewController.m

                - (void)viewDidLoad {    [super viewDidLoad];        self.view.backgroundColor = [UIColor blueColor];        //使用自定义的layout类//    MyLayout* myLayout = [[MyLayout alloc] init];//    myLayout.itemCount = 21;    CircleLayout* circleLayout = [[CircleLayout alloc] init];        UICollectionView* collectionView = [[UICollectionView alloc] initWithFrame: self.view.bounds collectionViewLayout: circleLayout];    collectionView.backgroundColor = [UIColor blackColor];    collectionView.dataSource = self;    collectionView.delegate = self;        [self.view addSubview: collectionView];    //    [collectionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier: @"MyUICollectionView"];    [collectionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier: @"CircleUICollectionView"];}- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {    return 1;}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return 11;}- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {//    UICollectionViewCell* myCell = [collectionView dequeueReusableCellWithReuseIdentifier: @"MyUICollectionView" forIndexPath: indexPath];    UICollectionViewCell* circleCell = [collectionView dequeueReusableCellWithReuseIdentifier: @"CircleUICollectionView" forIndexPath: indexPath];        circleCell.layer.masksToBounds = YES;    circleCell.layer.cornerRadius = 25;    circleCell.backgroundColor = [UIColor colorWithRed: arc4random() % 255 / 255.0 green: arc4random() % 255 / 255.0 blue: arc4random() % 255 / 255.0 alpha: 1.0];        return circleCell;}@end

                运行结果:

                总结

                UICollectionView其实算是特殊Flow布局的UITableView,但简单的列表仍可以使用UITableView

                UICollectionView最大的优势就是通过自定义Layout,实现cell的布局,整体的思路就是:通过一些几何计算,设置好每个item的布局位置和大小

                在之后的学习中,编者也将参考这片文章:一篇较为详细的 UICollectionView 使用方法总结

上一篇:文件服务器怎么设置?

下一篇:直播间怎么选服务器?