iOS瀑布流布局

###看完千篇一律的UI布局之后,当我们看到瀑布流的布局是不是觉得有种耳目一新的感觉呢?今天我们就说一下如果实现瀑布流,对于瀑布流,现在iOS中总共存在着三种实现方法.

  • 1.实现瀑布流的布局,我们需要计算每一张图片的尺寸大小,然后根据列数布局到我们的UIScrollView上去
  • 2.UITableView实现瀑布流效果,就是每一列都是一个视图.
  • 3.UICollectionView实现瀑布流就是对UICollectionView的UICollectionViewLayout重写

####实现思想: 就是把UICollectionView分成三列,由数组保存每一列的高度,然后每次设置UICollectionViewLayoutAttributes的时候,获取最短一列,计算出图片的size,然后添加到最短一列上面。

####具体代码

####自定义布局的实现.h

#import <UIKit/UIKit.h>
@class WaterLayout;

//协议
@protocol WaterLayoutDelegate <NSObject>

//代理方法 返回item的高度
- (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger )index itemWidth:(CGFloat )itemWidth;

@end


@interface WaterLayout : UICollectionViewLayout

@property (nonatomic,assign) CGFloat columnMargin;//列间距

@property (nonatomic,assign) CGFloat rowMargin;//行间距

@property (nonatomic,assign) UIEdgeInsets edge;//边缘间距

@property (nonatomic,assign) NSInteger columnCount;//列数

@property (nonatomic,assign) id<WaterLayoutDelegate> delegate;//代理


@end
复制代码

####自定义布局的实现.m


#import "WaterLayout.h"

@interface WaterLayout ()
@property (nonatomic,strong) NSMutableArray *attributesArray;   //存放所有cell的布局属性
@property (nonatomic,strong) NSMutableArray *allColumnMaxYArray; //所有列的高度
@property (nonatomic,assign) CGFloat contentSizeHeight;//内容的高度
@end
@implementation WaterLayout

- (NSMutableArray *)attributesArray {

    if (!_attributesArray) {
        _attributesArray = [NSMutableArray array];
    }

    return _attributesArray;

}


- (NSMutableArray *)allColumnMaxYArray {
    if (!_allColumnMaxYArray) {
        _allColumnMaxYArray  = [NSMutableArray array];
        
    }
    return _allColumnMaxYArray;


}
- (void)prepareLayout {

    [super prepareLayout];
    
    self.contentSizeHeight = 0;

     //先清空数组
    [self.allColumnMaxYArray removeAllObjects];
    
    for (NSInteger i = 0; i < self.self.columnCount; i++) {
        
        [self.allColumnMaxYArray addObject:@(self.self.edge.top)];
    }
    
    //开始创建每一个cell对应的布局属性
    //一共有多少个cell
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    
    for (int i = 0; i < count; i++) {
        
        //获取i位置上的索引
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        
        //获取每个cell的布局属性
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

        //添加
        [self.attributesArray addObject:attributes];
        
    }
    

    
}


/**
 *  这个方法会多次调用
 */
//cell的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    
 
    return self.attributesArray;
}



//indexPath对应cell的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {

    //为这个cell创建布局属性
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //collectionViewW
    CGFloat collectionViewW = self.collectionView.frame.size.width;
 
    
    //找出高度最短的那一列
     NSInteger column = 0;
    
    //默认第一列的高度最短
     CGFloat minColumnHeight = [self.allColumnMaxYArray[0] doubleValue];
    //遍历数组所有值
    for (NSInteger i = 1; i < self.self.columnCount; i++) {
        
      //取出每一列的高度
        CGFloat columnHeight = [self.allColumnMaxYArray[i] doubleValue];
        //判断高度
        if (minColumnHeight >columnHeight) {
            minColumnHeight = columnHeight;
            //最短列赋值给columnY
            column = i;
        }
        
    }
   
    
    //设置布局
    
    CGFloat w = (collectionViewW - self.edge.left - self.edge.right - (self.columnCount - 1)*self.self.columnMargin) / self.columnCount;
    
    CGFloat x = self.edge.left + column * (w + self.columnMargin);
    
    CGFloat y = minColumnHeight;
    
    //如果不是第一行时
    if (y != self.edge.top) {
        y += self.rowMargin;
    }
    
    //高度由外界决定,通过delegate
    CGFloat h = [self.delegate waterLayout:self heightForRowAtIndexPath:indexPath.row itemWidth:w];
    
    //设置frame
    attributes.frame = CGRectMake(x, y, w, h);
    
    //更新最短列的高度
    self.allColumnMaxYArray[column] = @(CGRectGetMaxY(attributes.frame));
    
    //记录最大高度
    CGFloat columHeight = [self.allColumnMaxYArray[column] doubleValue];
    if (self.contentSizeHeight < columHeight) {
        self.contentSizeHeight = columHeight;
    }
    
    return attributes;
}


//collectionView的ContentSize
- (CGSize)collectionViewContentSize {

 
    //最大高度+self.edge底部高度
    return CGSizeMake(0, self.contentSizeHeight+self.edge.bottom);
}
@end

复制代码

####外界使用布局方式


#import "ViewController.h"
#import "WaterLayout.h"
#import "ShopModel.h"
#import "ShopViewCell.h"
@interface ViewController ()<UICollectionViewDataSource,WaterLayoutDelegate>
@property (nonatomic,strong) NSMutableArray *shopModelArray;
@end

@implementation ViewController



- (NSMutableArray *)shopModelArray {

    if (!_shopModelArray) {
        _shopModelArray = [NSMutableArray array];
    }


    return _shopModelArray;

}


- (void)setData {


    NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"1.plist" ofType:nil]];

    for (NSDictionary *dic in array) {
        
        ShopModel *shop = [[ShopModel alloc] init];
        
        [shop setValuesForKeysWithDictionary:dic];
        
        [self.shopModelArray addObject:shop];
        
    }
  
}


- (void)viewDidLoad {
    [super viewDidLoad];
   
    //加载数据
    [self setData];

    [self setLayout];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)setLayout {

    WaterLayout *layout = [[WaterLayout alloc] init];
    
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
    collectionView.backgroundColor = [UIColor whiteColor];
    
    layout.delegate = self;
    layout.columnCount = 3;
    layout.columnMargin = 10;
    layout.rowMargin = 10;
    layout.edge = UIEdgeInsetsMake(10, 10, 10, 10);
    collectionView.dataSource =self;
    
    [self.view addSubview:collectionView];
    
    
    [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([ShopViewCell class]) bundle:nil] forCellWithReuseIdentifier:@"shop"];
}

- (NSInteger )numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;

}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {


    return self.shopModelArray.count;

}



- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ShopViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"shop" forIndexPath:indexPath];
 
    [cell setCellBasicInfoWithModel:self.shopModelArray[indexPath.row]];
 
    return cell;
}

#pragma mark -----waterLayoutDelegate
- (CGFloat)waterLayout:(WaterLayout *)waterLayout heightForRowAtIndexPath:(NSInteger)index itemWidth:(CGFloat)itemWidth {
    
    ShopModel *shop = self.shopModelArray[index];
    
    return itemWidth*shop.h/shop.w;

}

复制代码

######cell和model我就不展示了,显得代码占得太多了,只要会了思想,相信大家不难实现,在稍加封装,将上面的几个属性,写成代理方法,更加合理些.

转载于:https://juejin.im/post/5a332f386fb9a0450167ffc1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值