不同宽度Item布局
#import
NS_ASSUME_NONNULL_BEGIN
@class ZJCollectionLayout;
@protocol ZJCollectionLayoutDelegate
/** */
- (CGSize)flowLayout:(ZJCollectionLayout *) layout itemSizeForItemAtIndexPath:(NSIndexPath*)indexPath;
/** 每一列item之间的间距*/
- (CGFloat)itemColumnMarginInFlowLayout:(ZJCollectionLayout *) layout;
/** 每一行item之间的间距*/
- (CGFloat)itemRowMarginInFlowLayout:(ZJCollectionLayout *) layout;
/** 设置于collectionView边缘的间距*/
- (UIEdgeInsets)itemSectionInsetMarginInFlowLayout:(ZJCollectionLayout *) layout;
@end
@interface ZJCollectionLayout : UICollectionViewLayout
@property (nonatomic,weak) id
@end
NS_ASSUME_NONNULL_END
#import "ZJCollectionLayout.h"
@interface ZJCollectionLayout()
@property (strong,nonatomic)NSMutableArray * attrsArray; /** 存放每一个item的布局属性 */
@property (strong,nonatomic)NSMutableArray * sectionArray;/** count>0 表示换行 y 值计算方法改变*/
@property (assign,nonatomic)CGFloat columnMargin;
@property (assign,nonatomic)CGFloat rowMargin;
@property (assign,nonatomic)UIEdgeInsets sectionInset;
@property (strong,nonatomic)UICollectionViewLayoutAttributes *lastObject;
@end
@implementation ZJCollectionLayout
/** 懒加载 */
-(NSMutableArray *)attrsArray{
if (!_attrsArray){
_attrsArray = [NSMutableArray array];
}
return _attrsArray;
}
/** 懒加载 */
-(NSMutableArray *)sectionArray{
if (!_sectionArray){
_sectionArray = [NSMutableArray array];
}
return _sectionArray;
}
- (void)prepareLayout{
[super prepareLayout];
[self.attrsArray removeAllObjects];
[self setRowMargin:10];
[self setColumnMargin:10];
[self setSectionInset:UIEdgeInsetsMake(10, 10, 10, 10)];
NSInteger cou = [self.collectionView numberOfItemsInSection:0];
for (NSInteger i = 0 ; i< cou; i ++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArray addObject:attr];
}
}
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return self.attrsArray;
}
//返回指定indexPath的item的布局信息。子类必须重载该方法,该方法只能为cell提供布局信息,不能为补充视图和装饰视图提供。
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
CGFloat width = self.collectionView.frame.size.width;
CGSize frameSize = [self.delegate flowLayout:self itemSizeForItemAtIndexPath:indexPath];
//计算每一个item的位置
CGFloat lastObjectX = CGRectGetMaxX(self.lastObject.frame);
CGFloat x = lastObjectX+self.columnMargin;
CGFloat y = self.sectionInset.top;
if (x+frameSize.width+self.sectionInset.right>width) { // 换行
[self.sectionArray addObject:indexPath];
x = self.rowMargin;
CGFloat lastObjectY = CGRectGetMaxY(self.lastObject.frame);
y = lastObjectY+self.rowMargin;
}else if(self.sectionArray.count>0) {
y = self.lastObject.frame.origin.y;
}
//创建布局属性
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//设置item的frame
attrs.frame = CGRectMake(x, y, frameSize.width, frameSize.height);
[self setLastObject:attrs];
return attrs;
}
//返回collectionView内容区的宽度和高度,子类必须重载该方法,返回值代表了所有内容的宽度和高度,而不仅仅是可见范围的,collectionView通过该信息配置它的滚动范围,默认返回 CGSizeZero。
-(CGSize)collectionViewContentSize{
return CGSizeMake(0, CGRectGetMaxY(self.lastObject.frame)+self.sectionInset.bottom);
}
//该方法用来决定是否需要更新布局。如果collection view需要重新布局返回YES,否则返回NO,默认返回值为NO。子类重载该方法的时候,基于是否collection view的bounds的改变会引发cell和view布局的改变,给出正确的返回值。
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return NO;
}
#pragma mark -
- (CGFloat)columnMargin{
if([self.delegate respondsToSelector:@selector(itemColumnMarginInFlowLayout:)]){
return [self.delegate itemColumnMarginInFlowLayout:self];
}
return 10;
}
- (CGFloat)rowMargin{
if([self.delegate respondsToSelector:@selector(itemRowMarginInFlowLayout:)]){
return [self.delegate itemRowMarginInFlowLayout:self];
}
return 10;
}
- (UIEdgeInsets)sectionInset{
if([self.delegate respondsToSelector:@selector(itemSectionInsetMarginInFlowLayout:)]){
return [self.delegate itemSectionInsetMarginInFlowLayout:self];
}
return UIEdgeInsetsMake(10, 10, 10, 40);
}
@end