iOS ------ UICollectionView

一,UICollectionView的简介

UICollectionView是iOS6之后引入的一个新的UI控件,它和UITableView有着诸多的相似之处,其中许多代理方法都十分类似。简单来说,UICollectionView是比UITbleView更加强大的一个UI控件,有如下几个方面:

objectivec 复制代码
1.支持水平和垂直两种方向的布局
2.通过layout配置方式进行布局
3.类似于TableView的cell特性外,collectionView中的item大小和位置可以自由定义;
4.通过layout布局回调的代理方法,可以动态的定制每个item的大小和collection的大体布局属性
5.更加强大一点,完全自定义一套layout布局方案,可以实现意想不到的效果。

设置静态的布局

实现一个最简单的九宫格类布局

objectivec 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //创建一个layout布局类
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]  init];
    flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
    //flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    //flowLayout.itemSize = CGSizeMake((self.view.frame.size.width - 80) / 3, (self.view.frame.size.width - 80) / 3);
    //flowLayout.itemSize = CGSizeMake(100, 100 );
    //flowLayout.minimumLineSpacing = 20;
    //flowLayout.minimumInteritemSpacing = 20;
    flowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 20, 20);
    //创建collectionView,通过一个布局策略layout来创建
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flowLayout];
    //注册cell
    [self.collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    //设置代理
    self.collectionView.delegate = self;
    //设置数据源
    self.collectionView.dataSource = self;
    [self.view addSubview:self.collectionView];
}

这里有一点需要注意,collectionView在完成代理回调前,必须注册一个cell,类似如下:

objectivec 复制代码
//注册cell
    [self.collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:@"cell"];

这和tableView有些类似,又有些不同,因为tableView除了注册cell的方法外,还可以通过非注册的方法,当复用池中没有可用的cell时,可以返回nil,然后重新创建。

objectivec 复制代码
//tableView在从复用池中取cell的时候,有如下两种方法
//使用这种方式如果复用池中无,是可以返回nil的,我们在临时创建即可
- (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
//6.0后使用如下的方法直接从注册的cell类获取创建,如果没有注册 会崩溃
- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);

因为UICollectionView是iOS6.0之前的新类,因此这里统一了从复用池中获取cell的方法,没有再提供可以返回nil的方式,并且在UICollectionView的回调代理中,只能使用从复用池中获取cell的方式进行cell的返回,其他方式会崩溃。

objectivec 复制代码
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];
    return cell;
}

然后实现其他的代理方法

objectivec 复制代码
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 9;
}

上面我们写了一个简单九宫格的代码,所有的item都是一样大小的,但是有时候这样满足不了我们的需求,我们有时候可能也需要item不同大小。

在上面代码的基础上,删除控制item的大小的代码,再加入下面几行代码即可实现:

objectivec 复制代码
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.row % 2 == 0) {
        return CGSizeMake(50, 50);
    } else {
        return CGSizeMake(80, 80);
    }
}

设置动态布局

自定义FlowLayout进行瀑布流布局

首先,我们新建一个文件继承于UICollectionViewFlowLayout:

objectivec 复制代码
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

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

NS_ASSUME_NONNULL_END

前面说过,UICollectionViewFlowLayout是一个专门用来管理collectionView布局的类,因此,collectionView在进行UI布局前,会通过这个类的对象获取相关的布局信息,FlowLayout类将这些布局信息全部存放在了一个数组中,数组中是UICollectionViewLayoutAttributes类,这个类是对item布局的具体设置,以后咱们在讨论这个类。总之,**FlowLayout类将每个item的位置等布局信息放在一个数组中,在collectionView布局时,会调用FlowLayout类layoutAttributesForElementsInRect:方法来获取这个布局配置数组。因此,我们需要重写这个方法,返回我们自定义的配置数组,**另外,FlowLayout类在进行布局之前,会调用prepareLayout方法,所以我们可以重写这个方法,在里面对我们的自定义配置数据进行一些设置。

简单来说,自定义一个FlowLayout布局类就是两个步骤:

1、设计好我们的布局配置数据 prepareLayout方法中

2、返回我们的配置数组 layoutAttributesForElementsInRect方法中

objectivec 复制代码
#import "MyLayout.h"

@implementation MyLayout {
    NSMutableArray* attributeArray;
}
- (void)prepareLayout {
    attributeArray = [[NSMutableArray alloc] init];
    [super prepareLayout];
    float WIDTH = ([UIScreen mainScreen].bounds.size.width - self.sectionInset.left - self.sectionInset.right - self.minimumInteritemSpacing) / 2;
    
    CGFloat colHeight[2] = {self.sectionInset.top, self.sectionInset.bottom};
    
    for(int i = 0; i < self.itemCount; i++) {
        NSIndexPath* index = [NSIndexPath indexPathForItem:i inSection:0];
        
        UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        CGFloat height = arc4random() % 150 + 40;
        int width = 0;
        if (colHeight[0] < colHeight[1]) {
            colHeight[0] = colHeight[0] + height + self.minimumLineSpacing;
            width = 0;
        } else {
            colHeight[1] = colHeight[1] + height + self.minimumLineSpacing;
            width = 1;
        }
        attributes.frame = CGRectMake(self.sectionInset.left + (self.minimumInteritemSpacing + WIDTH) * width, colHeight[width] - height - self.minimumLineSpacing, WIDTH, height);
        [attributeArray addObject:attributes];
    }
    if (colHeight[0] > 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<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    return attributeArray;
}
@end

自定义完成FlowLayout后,在View Controller中使用

objectivec 复制代码
#import "ViewController.h"
#import "MyLayout.h"
#import "CollectionViewCell.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    MyLayout* layout = [[MyLayout alloc] init];
    layout.scrollDirection = UICollectionViewScrollDirectionVertical;
    layout.itemCount = 100;
    UICollectionView* collectView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
    collectView.delegate = self;
    collectView.dataSource = self;
    
    [collectView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    [self.view addSubview:collectView];
    // Do any additional setup after loading the view.
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 100;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.backgroundColor = [UIColor colorWithRed:arc4random() % 255 / 255.0 green:arc4random() % 255 / 255.0 blue:arc4random() % 255 / 255.0 alpha:1];
    return cell;
}
@end
相关推荐
goodSleep2 小时前
更新Mac OS Tahoe26用命令恢复 Mac 启动台时不小心禁用了聚焦搜索
macos
叽哥9 小时前
Flutter Riverpod上手指南
android·flutter·ios
用户091 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan1 天前
iOS26适配指南之UIColor
ios·swift
权咚2 天前
阿权的开发经验小集
git·ios·xcode
用户092 天前
TipKit与CloudKit同步完全指南
ios·swift
小溪彼岸2 天前
macOS自带截图命令ScreenCapture
macos
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
TESmart碲视2 天前
Mac 真正多显示器支持:TESmart USB-C KVM(搭载 DisplayLink 技术)如何实现
macos·计算机外设·电脑