iOS专题资源__UI专题移动开发iOS学习笔记

iOS 瀑布流不规则布局,分区拓展完善(collectionVi

2016-12-02  本文已影响500人  Bruce_XHG

写这篇文章的时候,其实网上已经有很多这样的文章或 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

上一篇下一篇

猜你喜欢

热点阅读