1 .CollectionView
CollectionView是tableView的升级版,可以理解为多列的tableView,用法也tableView也基本相同,但也有不同的
CollectionViewCell和TableViewCell一样,有cell,只是这里叫Item,我们可以规定Item的位置,但是这里item默认不具有cell的三大属性(imageView,textLabel,detailTextLabel),因此在设置cell的这些设置时,我们可以采用自定义MyCollectionViewCell,在这设置这些属性即可
2 .layout --- 也叫布局
UICollectionViewLayout是一个基类,是所有的布局文件的父类,但是里面并没有元素位置的定义
UICollectionViewFlowLayout是上面的一个子类,他实现了元素位置的定义,实现了流水式布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayoutalloc]init];
// 设置每一个元素的大小
layout.itemSize =CGSizeMake(100,100);
// 设置内边距大小
layout.sectionInset =UIEdgeInsetsMake(20,20, 40, 20);
// 设置滚动方向
// layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// 设置最小行间距
layout.minimumLineSpacing =50;
// 设置最小列间距
layout.minimumInteritemSpacing =10;
// 行间距的设置一定会实现,列间距的设置不一定会实现,因为存在剩余空间的平均分配问题
// 行间距因滚动方向的不同作用的效果方向也不同.
self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:layout];
[selfaddSubview:self.collection];
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row %2) {
return CGSizeMake(120, 120);
} else {
return CGSizeMake(80, 80);
}
}
3 .瀑布流
如果我们想要实现瀑布流的效果,需要对每一个item的size根据对应的image进行比例缩放,如果用系统自带的layout难以实现这个要求,因此我们只需自定义layout,其他不改变即可
基于UICollectionViewLayout创建WaterFlowLayout
WaterFlowLayout.h中
#import <UIKit/UIKit.h>
@protocol WaterFlowLayoutDelegate <NSObject>
// 通过indexPath位置的图片,根据图片的宽高的比例,以及item的width计算出indexPath的item的高度,最终通过在controller中指定代理,实现该方法
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterFlowLayout : UICollectionViewLayout
// 给自定义layout创建Layout所具备的以下几个属性
// Item的大小,最主要的是根据这个获取到列宽
@property (nonatomic,assign) CGSize itemSize;
// 内边距的设置
@property (nonatomic,assign) UIEdgeInsets sectionInsets;
// Item的间距
@property (nonatomic,assign) CGFloat spacing;
// 一共有几列
@property (nonatomic,assign) NSInteger numberOfColumns;
// 代理,用于绑定数据,计算高度的
@property (nonatomic,assign) id <WaterFlowLayoutDelegate>delegate;
@end
WaterFlowLayout.m中
@interfaceWaterFlowLayout ()
// 保存一共有几个Item
@property (nonatomic,assign) NSInteger numberOfItems;
// 保存计算好的每一个item的位置信息
@property (nonatomic,strong) NSMutableArray *itemAttributes;
// 保存每一列的高度
@property (nonatomic,strong) NSMutableArray *columnsHeights;
// 找到当前最长列的标号
- (NSInteger)indexForHeightestColumn;
// 找到当前最短列的标号
- (NSInteger)indexForShortestColumn;
@end
@implementation WaterFlowLayout
// 懒加载属性值
- (NSMutableArray *)columnsHeights {
if (_columnsHeights ==nil) {
_columnsHeights = [NSMutableArrayarray];
}
return_columnsHeights;
}
- (NSMutableArray *)itemAttributes {
if (_itemAttributes ==nil) {
_itemAttributes = [NSMutableArrayarray];
}
return_itemAttributes;
}
- (NSInteger)indexForHeightestColumn {
NSInteger index =0;
// 记录最长的长度
CGFloat length =0;
for (int i =0; i < self.numberOfColumns; i++) {
// 将数组里的对象转换成float类型的值
CGFloat currentValue = [self.columnsHeights[i]floatValue];
if (currentValue > length) {
length = currentValue;
index = i;
}
}
return index;
}
- (NSInteger)indexForShortestColumn {
NSInteger index =0;
CGFloat length =MAXFLOAT;
for (int i =0; i < self.numberOfColumns; i++) {
CGFloat currentValue = [self.columnsHeights[i]floatValue];
if (currentValue < length) {
length = currentValue;
index = i;
}
}
return index;
}
// 准备布局,在这里计算每一个Item的frame
- (void)prepareLayout {
[superprepareLayout];
// 拿到一共有多少个元素
self.numberOfItems = [self.collectionViewnumberOfItemsInSection:0];
// 给每一列添加一个top的高度
for (int i =0; i < self.numberOfColumns; i++) {
self.columnsHeights[i] =@(self.sectionInsets.top); // NSNumber
}
// 挨个去为每一个元素创建属性信息,并存放到数组中
for (int i =0; i < self.numberOfItems; i++) {
// 1 确定元素高度最短列
NSInteger shortestIndex = [selfindexForShortestColumn];
// 2 拿到最短列的高度备用
CGFloat height = [self.columnsHeights[shortestIndex]floatValue];
// 3 计算x的值 目标x = 内边距的左边距 + (宽 + Item间距) *列数
CGFloat detalX =self.sectionInsets.left + (self.itemSize.width + self.spacing) * shortestIndex;
// 4 计算y的值
CGFloat detalY = height +self.spacing;
// 5 创建属性
NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];
// 6 调用代理计算高度
CGFloat itemHeight =0;
if (_delegate && [_delegaterespondsToSelector:@selector(heightForItemIndexPath:)]) {
// 计算高度
itemHeight = [_delegateheightForItemIndexPath:indexPath];
}
// 7 生成frame
attributes.frame =CGRectMake(detalX, detalY, self.itemSize.width, itemHeight);
// 8 将这个信息对象放到数组里面
[self.itemAttributesaddObject:attributes];
// 9 更新这一列的高度
self.columnsHeights[shortestIndex] =@(detalY + itemHeight);
}
}
// 返回contentView的大小
- (CGSize)collectionViewContentSize{
// 求最高列的高度
NSInteger longestIndex = [selfindexForHeightestColumn];
CGFloat height = [self.columnsHeights[longestIndex]floatValue];
// 拿到contentView的原始大小
CGSize size =self.collectionView.frame.size;
size.height = height +self.sectionInsets.bottom;
return size;
}
// 返回每一个Item的Attributes(属性信息)
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
returnself.itemAttributes;
}
@end
创建完自定义Layout,就可以利用此WaterFlowLayout创建瀑布流的专属Layout
RootView.m中
// 使用瀑布流的专属Layout
self.layout = [[WaterFlowLayoutalloc] init];
// 设置属性
CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;
self.layout.itemSize =CGSizeMake(w, 10);
// 内边距
self.layout.sectionInsets =UIEdgeInsetsMake(10,10, 10, 10);
// item 间距
self.layout.spacing =10;
// 一共有几列
self.layout.numberOfColumns =3;
self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:self.layout];
[selfaddSubview:self.collection];
接受WaterFlowLayout中的代理,并指定代理为当前controller
实现代理中的方法
- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath {
// 拿到model
Model *m = self.data[indexPath.item];
// 获取图片宽度
CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;
CGFloat h = (w * m.height) / m.width;
return h;
}
model.h中
#import <Foundation/Foundation.h>
@interface Model : NSObject
@property (nonatomic,copy) NSString *thumbURL;
@property (nonatomic,assign) NSInteger width;
@property (nonatomic,assign) NSInteger height;
@end
model.m中
如果解析时用到添加字典到model
不要忘记 !!!
@implementation Model
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
}
@end