【iOS】UICollectionView的基本使用

时间:2024-10-08 12:45:18

UICollectionView是与UITableView相似的控件,不过它的布局更加*。

与UITableView的不同

tableView collectionView
初始化 需要指定布局style。 需要指定一个布局类。
子视图布局 一行代表一个cell,布局只需要考虑行高。 无视行列限制,一个item对应一个cell,由布局类来指定视图位置。
重用机制 针对cell,且非强制,某种cell也可以在非注册下使用。 针对所有子视图,且强制,必须注册才能使用。
重用机制调用初始化方法 在tableView的重用机制里,对于注册了的类,会在需要创建该类的对象的时候自动调用该类的initWithStyle:reuseIdentifier:方法。 在collectionView的重用机制里,对于注册了的类,会在需要该类的对象的时候自动调用该类的initWithFrame:方法。

以上摘自:/ohyeahhhh/article/details/51222590

UICollectionViewLayout与UICollectionViewFlowLayout简介

UICollectionViewLayout是一个layout对象,UICollectionView几乎所有的显示效果都由UICollectionViewLayout负责。

UICollectionViewFlowLayout是继承自UICollectionViewLayout的,是官方实现的流水布局效果,是一种非常经典的布局效果,应该也是我们最常用的。

UICollectionViewFlowLayout的一些基本属性:

  1. itemSize 每个item的大小;
  2. minimumLineSpacing 每行最小间距;
  3. minimumInteritemSpacing 每列最小间距;
  4. sectionInset 每个section的边距;
  5. scrollDirection 元素滚动方向。

流水式布局:
流布局是苹果预先定义的布局,这种布局就好比流水一样,将一个个cell按顺序排列。出来的效果跟网格差不多。

简单使用UICollectionView布置简单九宫格视图

  1. 初始化UICollecctionViewFlowLayout与UICollectionView。设置UICollectionView的delegate和dataSource。注意cell必须被注册才能使用。
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init];

    flowLayout.itemSize = CGSizeMake(100, 100);

    flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;

    flowLayout.minimumLineSpacing = 20;

    flowLayout.minimumInteritemSpacing = 20;

    flowLayout.sectionInset = UIEdgeInsetsMake(20, 20, 20, 20);

    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flowLayout];

    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];

    self.collectionView.delegate = self;
    self.collectionView.dataSource = self;
    [self.view addSubview:self.collectionView];
   
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  1. 完成协议方法(基本与tableView一致)。
- (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 10;
}

- (UICollectionViewCell*) collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [self.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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

效果:
在这里插入图片描述

自定义layout实现瀑布流布局

先放效果图:
在这里插入图片描述

UICollectionViewLayoutAttributes

首先介绍UICollectionViewLayoutAttributes类,它保存了每一个cell的大小位置等属性,每一个cell都有一个对应的UICollectionViewLayoutAttributes。UICollectionViewLayout正是通过它保存的信息进行布局。

涉及的方法

-(void)prepareLayout;
-(CGSize)collectionViewContentSize;
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;

  • -(void)prepareLayout; 在该方法用于计算各cell的位置和大小,并把它们封装成一个UICollectionViewLayoutAttributes。
  • -(CGSize)collectionViewContentSize; 该方法返回ContentView的大小。
  • -(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; 该方法返回包含所有子视图的UICollectionViewLayoutAttributes对象的数组。

具体步骤

  1. 创建一个继承自UICollectionViewFlowLayout的类,添加一个itemCount。
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyLayout : UICollectionViewFlowLayout

@property (nonatomic, assign) int itemCount;

@end

NS_ASSUME_NONNULL_END
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1. 在实现部分添加一个NSMutableArray的成员变量,用于储存所有子视图的UICollectionViewLayoutAttributes对象。
  2. 重写-(void)prepareLayout;在该方法内计算每个cell的位置和大小,并把它们封装成一个UICollectionViewLayoutAttributes对象,添加到专门保存UICollectionViewLayoutAttributes对象的成员变量中。下面是代码:
- (void) prepareLayout {
    attributeArray = [[NSMutableArray alloc] init];
    [super prepareLayout];
    
    // 计算每个item的宽度
    float WIDTH = ([UIScreen mainScreen].bounds.size.width - self.minimumInteritemSpacing - self.sectionInset.left - self.sectionInset.right) / 2;
    
    // 这个数组用于储存当前左右两列瀑布流的长度,保证新的item添加在短的一边下面。
    CGFloat colHight[2] = {0};
    
    // 循环计算每个item的位置大小
    for (int i = 0; i < self.itemCount; i++) {
    	// 获取index
        NSIndexPath* index = [NSIndexPath indexPathForItem:i inSection:0];
        
        // 根据index创建attributes对象
        UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        
        // 随机一个高度,在40-190之间
        CGFloat hight = arc4random()%150 + 40;
        
        // 标记最短的列
        int width = 0;
        // 将新的item的高度加到最短的列下
        if (colHight[0] < colHight[1]) {
            colHight[0] = colHight[0] + hight + self.minimumLineSpacing;
            width = 0;
        } else {
            colHight[1] = colHight[1] + hight + self.minimumLineSpacing;
            width = 1;
        }
        // 将改item的位置和大小封装成UICollectionViewLayoutAttributes对象
        attributes.frame = CGRectMake(self.sectionInset.left + (self.minimumInteritemSpacing + WIDTH) * width, colHight[width] - hight - self.minimumLineSpacing, WIDTH, hight);
        // 保存UICollectionViewLayoutAttributes对象
        [attributeArray addObject:attributes];
    }
    
    // 通过预设itemSize的大小保证滑动范围的正确(取一个高度上的平均值),也可以通过重写`-(CGSize)collectionViewContentSize; `方法完成
    if (colHight[0] > colHight[1]) {
        self.itemSize = CGSizeMake(WIDTH, ((colHight[0] - self.sectionInset.top) * 2 / self.itemCount - self.minimumLineSpacing));
    } else {
        self.itemSize = CGSizeMake(WIDTH, ((colHight[1] - self.sectionInset.top) * 2 / self.itemCount - self.minimumLineSpacing));
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  1. 重写-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; 方法返回包含所有子视图的UICollectionViewLayoutAttributes对象的数组。
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    return attributeArray;
}
  • 1
  • 2
  • 3
  1. 初始化CollectionView。
- (void) getMyLayout {
    MyLayout* layout = [[MyLayout alloc] init];
    layout.scrollDirection = UICollectionViewScrollDirectionVertical;
    layout.itemCount = 100;
    layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
    self.collectionView.delegate = self;
    self.collectionView.dataSource = self;
    
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
    
    [self.view addSubview:self.collectionView];
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. 完成协议方法。
- (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return 100;
}

- (UICollectionViewCell*) collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [self.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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14