看完千篇一律的UI布局之后,当我们看到瀑布流的布局是不是觉得有种耳目一新的感觉呢?今天我们就说一下如果实现瀑布流,对于瀑布流,现在iOS中总共存在着三种实现方法.
瀑布流.gif
- 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;
}
网友评论