自定义UICollectionViewFlowLayout布局
代码直接奉上:
----h文件---
#import <UIKit/UIKit.h>
@interface VerticalCollectionAnyCenterLayout : UICollectionViewFlowLayout
//传入一个item'的大小跟、行距离、自动计算布局等、
-(instancetype)initWithItemSize:(CGSize)size lineSpace:(CGFloat)margin_line;
@end
----m文件---
#import "VerticalCollectionAnyCenterLayout.h"
@interface VerticalCollectionAnyCenterLayout()
@property(nonatomic,strong)NSMutableArray * attrsArr;
@property (nonatomic,assign)NSInteger rows_line;//需要手动计算
@property (nonatomic,assign)CGFloat margin_inter;//需要手动计算item之间的距离
@property (nonatomic,assign)CGFloat margin_line;
@property (nonatomic,assign)CGSize size_item;
@end
@implementation VerticalCollectionAnyCenterLayout
-(instancetype)initWithItemSize:(CGSize)size lineSpace:(CGFloat)margin_line{
if (self = [super init]){
self.margin_line = margin_line;
self.size_item = size;
}
return self;
}
-(void)caculation{
[self.collectionView setNeedsLayout];
CGSize size_collection = self.collectionView.bounds.size;
self.rows_line = (NSInteger)size_collection.width / self.size_item.width;
self.margin_inter = ((CGFloat)(size_collection.width - self.rows_line * self.size_item.width)) / ((CGFloat)(self.rows_line + 1));
self.itemSize = self.size_item;
self.minimumLineSpacing = self.margin_line;
self.minimumInteritemSpacing = self.margin_inter;
}
#pragma mark ---- 懒加载
-(NSMutableArray *)attrsArr
{
if(!_attrsArr){
_attrsArr=[[NSMutableArray alloc] init];
}
return _attrsArr;
}
-(void)prepareLayout
{
[super prepareLayout];
[self caculation];
[self.attrsArr removeAllObjects];
[self creatAttrs];
}
-(void)creatAttrs{
//计算出每组有多少个
NSInteger count=[self.collectionView numberOfItemsInSection:0];
/**
* 因为不是继承流水布局 UICollectionViewFlowLayout
* 所以我们需要自己创建 UICollectionViewLayoutAttributes
*/
//如果是多组的话 需要2层循环
for (int i=0; i<count; i++) {
//创建UICollectionViewLayoutAttributes
NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
UICollectionViewLayoutAttributes * attrs=[self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArr addObject:attrs];
}
}
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
// 特别注意 在这个方法里 可以边滑动边刷新(添加) attrs 一劳永逸 如果只需要添加一次的话 可以把这些 prepareLayout方法中去
return self.attrsArr;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange{
return YES;
}
#pragma mark ---- 这个方法需要返回indexPath位置对应cell的布局属性
/**
* //TODO: 这个方法主要用于 切换布局的时候 如果不适用该方法 就不会切换布局的时候会报错
* reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0xc000000000400016> {length = 2, path = 0 - 2}'
*/
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
// 主要是返回每个indexPath的attrs
//创建UICollectionViewLayoutAttributes
//这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
//计算出每组有多少个
NSInteger section = indexPath.section;
NSInteger count=[self.collectionView numberOfItemsInSection:section];
UICollectionViewLayoutAttributes * attrs=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSInteger yushu = count % self.rows_line;
NSInteger zhengshu = count / self.rows_line;
NSInteger start = zhengshu * self.rows_line;
if (indexPath.row >= start){
//默认单行每个item都是等宽度
CGFloat left_right_margin = (self.collectionView.bounds.size.width -
self.size_item.width * yushu - (yushu - 1) * self.margin_inter) /2;
NSInteger index_last_line =indexPath.row - start;
CGRect frame = attrs.frame;
attrs.size = self.size_item;
frame.size = self.size_item;
frame.origin.x = left_right_margin + (self.margin_inter + self.size_item.width) * index_last_line;
frame.origin.y = (self.margin_line + self.size_item.height) * (indexPath.row / self.rows_line)+ self.margin_line;
attrs.frame = frame;
}
else
{
CGRect frame = attrs.frame;
frame.size = self.size_item;
attrs.size = self.size_item;
frame.origin.x = (self.margin_inter + self.size_item.width) * (indexPath.row % self.rows_line) + self.margin_inter;
frame.origin.y = (self.margin_line + self.size_item.height) * (indexPath.row / self.rows_line) + self.margin_line;
attrs.frame = frame;
}
if (indexPath.row == (count - 1)){///最后一个、计算contenSize
CGSize contentSize = self.collectionView.contentSize;
CGRect frame_last = attrs.frame;
contentSize.height = CGRectGetMaxY(frame_last);
self.collectionView.contentSize = contentSize;
}
return attrs;
}
@end
QQ20180810-0.png
使用方法直接给collectionView 一个layout即可、不用在代理中返回偏移量和itemSize