瀑布流的实现全过程

1.创建继承自UICollectionViewCell的l类ImageCell,将imageView和label声明成属性,然后重写- initWithFrame:方法,初始化内部控件

- (id)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        [self setupSubviews];

    }

    return self;

}

 

- (void)setupSubviews

{

    _imageView = [[UIImageView allocinitWithFrame:self.bounds];

    [self.contentView addSubview:_imageView];

    _numberLabel = [[UILabel allocinitWithFrame:CGRectMake(005020)];

    [_imageView addSubview:_numberLabel];

    

}

- (void)layoutSubviews

{

    [super layoutSubviews];

    

    _imageView.frame = self.bounds;

}

2:创建模型Model类,声明好属性

- (void)setValue:(id)value forUndefinedKey:(NSString *)key

{

//    if ([key isEqualToString:@"id"]) {

//        self.ID = value;

}

 

- (void)setValue:(id)value forKey:(NSString *)key

{

    [super setValue:value forKey:key];

    

    if ([key isEqualToString:@"width"]) {

        

        self.width = [value floatValue];

    }

    

    if ([key isEqualToString:@"height"]) {

        

        self.height = [value floatValue];

    }

    

}

 

3:创建一个瀑布流的布局类继承自NSObject,然后设置代理协议,并声明属性  

 

4:在这个自定义的WaterFlowLayout中实现各种布局方法

//存放每一列的高度

@property (nonatomic, retain) NSMutableArray *columnHeightsArray;

 

//存放 每一个item 属性 包含 frame以及下标

@property (nonatomic, retain) NSMutableArray *attributesArray;

 @end

 

//获取最小高度的方法

- (CGFloat)minHeight

{

    CGFloat min = 100000;

    for (NSNumber *height in _columnHeightsArray) {

        CGFloat h = [height floatValue];

        if (min > h) {

            min = h;

        }

    }

    return min;

}

 

//获取最大值

- (CGFloat)maxHeight

{

    CGFloat max = 0;

    for (NSNumber *height in _columnHeightsArray) {

        CGFloat h = [height floatValue];

        if (max < h) {

            max = h;

        }

    }

    return max;

}

//最小高度的下标

- (NSUInteger)indexOfMinHeight

{

    NSUInteger index = 0;

    for (int i = 0; i < [_columnHeightsArray count]; i ++) {

        CGFloat height = [_columnHeightsArray[i] floatValue];

        if (height == [self minHeight]) {

            index = i;

            return index;

        }

    }

    return index;

}

 

//重写父类的布局方法

- (void)prepareLayout

{

    [super prepareLayout];

    

    _attributesArray = [[NSMutableArray alloc] init];

    

    _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];

    

    //给列高数组里面的对象赋初值

    for (int i = 0; i < self.numberOfColumn; i ++) {

        [_columnHeightsArray addObject:@0.0];

    }

    

    CGFloat totalWidth = self.collectionView.frame.size.width;

    

    //创建 每个item frame中的xy

    CGFloat x = 0;

    CGFloat y = 0;

    

    NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];

    

    for (int i = 0; i < itemCount; i ++) {

        //得到集合视图中 列间隙的个数

        NSUInteger numberOfSpace = self.numberOfColumn - 1;

        

        //代理对象执行代理方法,得到 item之间的间隙大小

        CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0];

        

        //求每列的宽度,也就是每个itemwidth

        CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;

        

        

        //获取每一个itemSize的大小

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

        

        //数据中原始图片大小

        CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];

    

        //通过 约分公式得到固定宽之后的高度是多少

        CGFloat height = width * imageSize.height / imageSize.width;

        

        

        UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

        

        //记录每一个item的大小和位置

        attribute.frame = CGRectMake(x, y, width, height);

        

        //数组保存每个item的位置信息

        [_attributesArray addObject:attribute];

        

        NSLog(@"item = %d",i);

        NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);

        

        //求列高最小的那一列的下标

        NSUInteger minHeightIndex = [self indexOfMinHeight];

        

        //求出最小列的高度

        CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];

        

        //求出行高

        CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];

        

        //上一次总的列高 加上 行高 加上新加上的itemheight,才是现在这一列的总高度

        //minHeight为最小列现在的高度

        //lineHeight为行间距

        //height为新加的item的高

        _columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];

        

        //重新算最小列高的下标

        minHeightIndex = [self indexOfMinHeight];

        

        //算下一次新加的itemxy

        x = (spaceWidth + width) * minHeightIndex;

        

        y = [self minHeight];

    }

}

 

//重写这个方法,可以返回集合视图的总高度

- (CGSize)collectionViewContentSize

{

    return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]);

}

 

//这个方法不写 集合视图显示不出来,这个方法是将保存的每个item的信息告诉集合视图,进行显示。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

    return _attributesArray;

}

 //这是重写的一个布局方法,和系统的布局方法就不一样了,然后就可以将这个类当成系统的UICollectionFlowLayout相同的方法使用了

 

#pragma mark -----WaterFlowDelegate-----

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

{

    Model *model = _dataArray[indexPath.row];

    return CGSizeMake(model.width, model.height);

}

 

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section

{

    return UIEdgeInsetsMake(0, 0, 0, 0);

}

 

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section

{

    return 10;

}

 

 

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section

{

    return 5;

}

 

- (void)viewDidLoad {

    [super viewDidLoad];

//bundle文件中读取原始数据  json格式

    NSString * filePath = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"];

    NSData * sourceData = [NSData dataWithContentsOfFile:filePath];

    

    //解析

    NSArray * sourceArray = [NSJSONSerialization JSONObjectWithData:sourceData options:NSJSONReadingMutableContainers error:nil];

    

    self.dataArray = [NSMutableArray arrayWithCapacity:40];

    

    //处理数据

    for (NSDictionary * dic in sourceArray) {

        

        Model * m = [[Model alloc] init];

        [m setValuesForKeysWithDictionary:dic];

        [_dataArray addObject:m];

        [m release];

    }

    

    //创建布局对象

    WaterFlowLayout *flowLayout = [[WaterFlowLayout alloc] init];

    

    flowLayout.delegate = self;

    flowLayout.numberOfColumn = 3;

    

    //创建集合视图

    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];

    collectionView.backgroundColor = [UIColor whiteColor];

    

    collectionView.delegate = self;

    collectionView.dataSource = self;

    

    //collectionView注册一个cell

    [collectionView registerClass:[ImageCell class] forCellWithReuseIdentifier:@"aaa"];

    

    [self.view addSubview:collectionView];

    

    [collectionView release];

    [flowLayout release];

    

    // Do any additional setup after loading the view, typically from a nib.

}

 

#pragma mark -----DataSource-----

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

{

    return [_dataArray count];

}

 

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{

    ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"aaa" forIndexPath:indexPath];

    

    

    //获取模型

    Model *model = self.dataArray[indexPath.row];

    

    NSURL *url = [NSURL URLWithString:model.thumbURL];

    

    [cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"屏幕快照 2016-02-25 下午4.17.55.png"]];

    

//    cell.imageView.image = [UIImage imageNamed:@"8.png"];

    

//    cell.numberLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];

    

    return cell;

}

这里需要用到一个类SDWebImage的文件,将它上传到了我的github上。

 

 

 

 

原文地址:https://www.cnblogs.com/arenouba/p/5217838.html