美文网首页iOS专题资源__UI专题移动开发iOS学习笔记
iOS 瀑布流不规则布局,分区拓展完善(collectionVi

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

作者: Bruce_XHG | 来源:发表于2016-12-02 11:24 被阅读500次

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

    相关文章

      网友评论

      • 沐时:楼主,你好,我有两个问题想咨询你一下,不同分区不同布局和分区间距该如何创建,希望指教?

      本文标题:iOS 瀑布流不规则布局,分区拓展完善(collectionVi

      本文链接:https://www.haomeiwen.com/subject/nngfmttx.html