UICollectionView是与UITableView相似的控件,不过它的布局更加自由。
tableView | collectionView | |
---|---|---|
初始化 | 需要指定布局style。 | 需要指定一个布局类。 |
子视图布局 | 一行代表一个cell,布局只需要考虑行高。 | 无视行列限制,一个item对应一个cell,由布局类来指定视图位置。 |
重用机制 | 针对cell,且非强制,某种cell也可以在非注册下使用。 | 针对所有子视图,且强制,必须注册才能使用。 |
重用机制调用初始化方法 | 在tableView的重用机制里,对于注册了的类,会在需要创建该类的对象的时候自动调用该类的initWithStyle:reuseIdentifier:方法。 | 在collectionView的重用机制里,对于注册了的类,会在需要该类的对象的时候自动调用该类的initWithFrame:方法。 |
以上摘自:https://blog.csdn.net/ohyeahhhh/article/details/51222590
UICollectionViewLayout是一个layout对象,UICollectionView几乎所有的显示效果都由UICollectionViewLayout负责。
UICollectionViewFlowLayout是继承自UICollectionViewLayout的,是官方实现的流水布局效果,是一种非常经典的布局效果,应该也是我们最常用的。
UICollectionViewFlowLayout的一些基本属性:
流水式布局:
流布局是苹果预先定义的布局,这种布局就好比流水一样,将一个个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];
}
- (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;
}
首先介绍UICollectionViewLayoutAttributes类,它保存了每一个cell的大小位置等属性,每一个cell都有一个对应的UICollectionViewLayoutAttributes。UICollectionViewLayout正是通过它保存的信息进行布局。
-(void)prepareLayout;
-(CGSize)collectionViewContentSize;
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect;
-(void)prepareLayout;
在该方法用于计算各cell的位置和大小,并把它们封装成一个UICollectionViewLayoutAttributes。-(CGSize)collectionViewContentSize;
该方法返回ContentView的大小。-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
该方法返回包含所有子视图的UICollectionViewLayoutAttributes对象的数组。#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface MyLayout : UICollectionViewFlowLayout
@property (nonatomic, assign) int itemCount;
@end
NS_ASSUME_NONNULL_END
-(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));
}
}
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
方法返回包含所有子视图的UICollectionViewLayoutAttributes对象的数组。- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
return attributeArray;
}
- (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];
}
- (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;
}