寫這篇文章的時候,其實網上已經有很多這樣的文章或 demo. 但是我在看的時候還是遇到了一點需要注意的地方.所以決定再寫一篇,說明一下我看網上的 demo 沒有注意到的地方.
1.寫之前先看一下大致的效果圖,如果不是你需要的 也就沒必要看下去,浪費你的時間了.
效果圖如下(可以設置參數,實現多列的效果)
2.該瀑布流多見于電商里面的商品展示布局.
3.說一下我在寫的時候遇到問題:? 紫色的是 imageView,我用 masonry 布局,設置 imageView 大小和 item 的大小一致,然后上下滑動的時候就出現了imageView 的 frame 和 item 的 frame 大小不一致的情況.
4.上面就是我遇到的問題,網上的 demo 大部分就是直接是 item,item 上面沒有放其他的控件,所以沒有這種問題.其實也主要是約束的問題. 下面把代碼貼出來和大家分享一下.
1.重寫 layout 布局
typedef CGFloat (^HeightBlock)(NSIndexPath *indexPath);
@interface MyCollectionViewLayout : UICollectionViewLayout
-(instancetype)initWithItemsHeightBlock:(HeightBlock)block;
@property (nonatomic,assign) NSInteger sectionCount;? //分區(qū)數
@property (nonatomic,assign) CGFloat colMargin;? //列間距
@property (nonatomic,assign) CGFloat colCount;? //列數
@property (nonatomic,assign) CGFloat rolMargin;? //行間距
@property (nonatomic,strong) NSMutableArray *colsHeight;? //每列總高度
@property (nonatomic,assign) CGFloat colWidth;? //列寬
@property (nonatomic,strong) HeightBlock heightBlock;
@end
@implementation MyCollectionViewLayout
-(instancetype)initWithItemsHeightBlock:(HeightBlock)block{
? self = [super init];??
if (self) {??
? ? self.heightBlock = block;? ??
? _sectionCount = 1; //默認分區(qū)數1? ? ?
? _colMargin = 5; //默認列間距5? ? ?
? _colCount = 4;? //默認列數 4 列?
? }? ?
return self;
}
-(NSMutableArray *)colsHeight{
? ? if (!_colsHeight) {?
? ? ? NSMutableArray *array = [NSMutableArray array];? ? ??
for (int i = 0; i < _colCount; i++) {? ? ? ? ? ? //這里可以設置初始高度? ? ? ? ??
[array addObject:@(0)];? ? ??
}? ? ?
? _colsHeight = [array mutableCopy];?
? }?
? return _colsHeight;
}
#pragma mark - 重寫下面系統(tǒng)的方法
//重新布局
-(void)prepareLayout{?
? [super prepareLayout];? ?
self.colWidth = (self.collectionView.frame.size.width - (self.colCount+1)*self.colMargin)/self.colCount;? ? self.colsHeight = nil;
}
//設置內容尺寸
-(CGSize)collectionViewContentSize{
? NSNumber *longest = self.colsHeight[0];??
for (int i = 0; i < self.colsHeight.count; i++) {
? ? ? NSNumber *rolHeight = self.colsHeight[i];?
? ? ? if (longest.floatValue < rolHeight.floatValue) {
? ? ? ? ? ? longest = rolHeight;? ? ??
}? ?
}? ?
return CGSizeMake(self.collectionView.frame.size.width, longest.floatValue);
}
//設置每個 item 的屬性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
? UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];?
? NSNumber *shortest = self.colsHeight[0];??
NSInteger shortCol = 0;?
? for (int i = 0; i < self.colsHeight.count; i++) {? ?
? ? NSNumber *rolHeight = self.colsHeight[i];??
? ? if (shortest.floatValue > rolHeight.floatValue) {? ? ??
? ? shortest = rolHeight;? ? ? ? ? ? shortCol = i;? ? ??
}? ?
}??
CGFloat x = (shortCol+1)*self.colMargin + shortCol*self.colWidth;?
? CGFloat y = shortest.floatValue + self.colMargin;? ??
? CGFloat height = 0;??
if (self.heightBlock) {? ?
? ? height = self.heightBlock(indexPath);?
? }?
? attributes.frame = CGRectMake(x, y, self.colWidth, height);??
self.colsHeight[shortCol] = @(shortest.floatValue + self.colMargin + height);??
return attributes;
}
//獲取每個 item 的屬性
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *mutArr = [NSMutableArray array];
for (int j = 0; j < _sectionCount; j++) {
NSInteger items = [self.collectionView numberOfItemsInSection:j];
for (int i = 0; i < items; i++) {
UICollectionViewLayoutAttributes *att = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:j]];
[mutArr addObject:att];
}
}
return mutArr;
}
//這個方法是在 cell 重新布局時調用 repareLayout 方法
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
@end
2.自定義 cell 里面需要注意的問題
@implementation Collection2ViewCell
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
//獲取當前 cell 的寬和高
self.imageView = [UIImageView new];
self.imageView.backgroundColor = [UIColor purpleColor];
[self.contentView addSubview:self.imageView];
[self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {//注意這里給的是約束
make.edges.equalTo(self.contentView);
}];
//下面這種寫法就會造成上面我說的那種問題(具體原因是 item 的復用問題造成的,復用的時候不會再走該方法,但是 item 的高度賦值是會走的,所以造成 imageView 的 frame 和 cell 的 frame 不一致的情況)
//? ? ? ? [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
//? ? ? ? ? ? make.centerX.mas_equalTo(self.mas_centerX);
//? ? ? ? ? ? make.centerY.mas_equalTo(self.mas_centerY);
//? ? ? ? ? ? make.width.mas_equalTo(frame.size.width);
//? ? ? ? ? ? make.height.mas_equalTo(frame.size.height);
//? ? ? ? }];
}
return self;
}
3.控制器里面的代碼
@interface Collection2ViewController ()
@property (nonatomic,strong) NSMutableArray *itemHeightArr;
@property (nonatomic,strong) MyCollectionViewLayout *flowLayout;
@property (nonatomic,strong) UICollectionView *collectionView;
@end
@implementation Collection2ViewControllerstatic
NSString * const reuseIdentifier = @"Cell";
- (void)viewDidLoad {?
? [super viewDidLoad];
? self.view.backgroundColor = [UIColor colorWithHexString:@"999999"];?
? self.title = @"UnNormalCollectionView";? ?
[self.view addSubview:self.collectionView];
}
-(UICollectionView *)collectionView{
? ? if (!_collectionView) {
? ? ? ? _collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, kWidth, kHeight-64) collectionViewLayout:self.flowLayout];? ??
? _collectionView.dataSource = self;? ??
? _collectionView.delegate = self;? ? ?
? _collectionView.backgroundColor = [UIColor whiteColor];? ? ?
? [_collectionView registerClass:[Collection2ViewCell class] forCellWithReuseIdentifier:reuseIdentifier];??
}? ?
return _collectionView;
}
-(UICollectionViewLayout *)flowLayout{
? if (!_flowLayout) {? ??
? _flowLayout = [[MyCollectionViewLayout alloc] initWithItemsHeightBlock:^CGFloat(NSIndexPath *indexPath) {? ??
? ? ? return [self.itemHeightArr[indexPath.item]floatValue];? ? ??
}];? ?
? ? _flowLayout.colCount = 2;? ? ?
? _flowLayout.sectionCount = 1;?
? }?
? return _flowLayout;
}
-(NSMutableArray *)itemHeightArr{??
if (!_itemHeightArr) {??
? ? NSMutableArray *arr = [NSMutableArray array];? ?
? ? for (int i = 0; i < 100; i++) {?
? ? ? ? ? [arr addObject:@(arc4random()%50+80)];? ??
? }?
? ? ? _itemHeightArr = [arr copy];
? }
? return _itemHeightArr;
}
#pragma mark-
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.itemHeightArr.count;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"點擊的是第 %ld 個item",indexPath.row);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Collection2ViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor redColor];
return cell;
}
@end