写这篇文章的时候,其实网上已经有很多这样的文章或 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; //分区数
@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; //默认分区数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 - 重写下面系统的方法
//重新布局
-(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
网友评论