您的位置:首页 > 其它

自定义瀑布流

2016-04-05 09:13 218 查看

DKFlowLayout类

DKFlowLayout.h

// 在.h里@class, 在.m里#import
@class DKFlowLayout;

@protocol DKFlowLayoutDelegate <NSObject>

- (CGFloat) layout: (DKFlowLayout *)layout heightForItemAtIndexPath:(NSIndexPath *) indexPath width: (CGFloat) width;

@end

@interface DKFlowLayout : UICollectionViewLayout

// 指定有多少列(一般2到4列)
@property (nonatomic, assign) NSInteger columnCounts;
// 设置距离屏幕四周的边界距离
@property (nonatomic, assign) UIEdgeInsets edgeInsets;
// 列间距
@property (nonatomic, assign) NSInteger columnSpace;
// 行间距
@property (nonatomic, assign) NSInteger rowSpace;

@property (nonatomic, assign) id<DKFlowLayoutDelegate> delegate;

@end


DKFlowLayout.m

#define kWidth self.collectionView.frame.size.width

@interface DKFlowLayout ()
// 用来保存每一列的 Y 值
@property (nonatomic, retain) NSMutableDictionary *columnDic;
// 用来存放 item 的 attribute 对象
@property (nonatomic, retain) NSMutableArray *attributsArray;

@end

@implementation DKFlowLayout

// 1.初始化方法
- (instancetype) init {
if (self = [super init]) {
self.columnDic = [NSMutableDictionary dictionary];
self.attributsArray = [NSMutableArray array];
}
return self;
}

// 2.prepareLayout方法: collectionView 布局 item 的时候,该方法会被执行
- (void) prepareLayout {
[super prepareLayout];

// 根据列数进行遍历, 给起始的每列都加上上边界的距离
for (NSInteger i = 0; i < self.columnCounts; i++) {
NSString *key = [NSString stringWithFormat:@"%ld", i];
self.columnDic[key] = @(self.edgeInsets.top);
}

// 获取 collectionView 上 item 的个数
NSInteger count = [self.collectionView numberOfItemsInSection:0];
// 循环遍历每个 item
for (int i = 0; i < count; i++) {
[self setItemFrame:i];
}
}
// 3.自定义一个方法设置每个 item 的信息
- (void) setItemFrame: (NSInteger) index {
// 1.首先获取当前最短的那一列
// 2.设置每个 item 的 frame 的值

// 初始化一个字符串,用它来记录当前最短的列的下标
__block NSString *minColumn = @"0";
// 遍历字典的每个 key 和 value
[self.columnDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
// 如果遍历得到的值小于默认列的值,就将 key 的值赋值到 minColumn 里
if ([obj floatValue] < [self.columnDic[minColumn] floatValue]) {
minColumn = key;
}
}];

// 宽 = (屏幕宽 - 左边界 - 右边界 - 列间距 * (列数 - 1)) / 列数
CGFloat width = (kWidth - self.edgeInsets.left - self.edgeInsets.right - self.columnSpace * (self.columnCounts - 1)) / self.columnCounts;
// x = 左边距 + (宽 + 列间距) * 列的下标(对应当前最短那列的下标)
CGFloat x = self.edgeInsets.left + (width + self.columnSpace) * [minColumn floatValue];
// 创建一个 indexPath
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
// 高
CGFloat height = [self.delegate layout:self heightForItemAtIndexPath:indexPath width:width];
// Y
// 先找到当前最短那列的 Y 值
CGFloat minY = [self.columnDic[minColumn] floatValue];
// 为最短的列更新 Y 轴的高度 = minY + 高 + 行间距
self.columnDic[minColumn] = @(minY + height + self.rowSpace);

// UICollectionViewLayoutAttributes: 设置 item
4000
的 frame, bounds, 透明度等属性
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attribute.frame = CGRectMake(x, minY, width, height);
[self.attributsArray addObject:attribute];
}

// 4.把所有样式返回,告诉系统如何去布局
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
return self.attributsArray;
}

// 5.设置滚动的范围
- (CGSize) collectionViewContentSize {
// 滚动范围以最长的列作为依据
__block NSString *maxY = @"0";
[self.columnDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
if ([obj floatValue] > [self.columnDic[maxY] floatValue]) {
maxY = key;
}
}];
CGFloat h = [self.columnDic[maxY] floatValue] + self.edgeInsets.bottom;
return CGSizeMake(0, h);
}

@end


MyCell类

MyCell.h

@interface MyCell : UICollectionViewCell
@property (nonatomic, retain) UIImageView *picImageView;
@property (nonatomic, retain) Picture *pic;
@end


MyCell.m

@implementation MyCell

- (instancetype) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.picImageView = [[UIImageView alloc] init];
[self.contentView addSubview:self.picImageView];
}
return self;
}

- (void) layoutSubviews {
[super layoutSubviews];
// 为了避免重用之后造成子视图上的尺寸有问题, 所以在 layoutSubviews 方法重新设置子视图的尺寸
self.picImageView.frame = self.contentView.frame;
}

// 重写 cell 的 set 方法
- (void) setPic:(Picture *)pic {
if (_pic != pic) {
[_pic release];
_pic = [pic retain];
}
[self.picImageView sd_setImageWithURL:[NSURL URLWithString:_pic.thumbURL]];
}

@end


Picture类

.h

@interface Picture : NSObject
@property (nonatomic, copy) NSString *thumbURL;
@property (nonatomic, copy) NSNumber *width;
@property (nonatomic, copy) NSNumber *height;
@end


eg.

- (void) createData {
NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSArray *tempArr = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.arr = [NSMutableArray array];
for (NSDictionary *dic in tempArr) {
Picture *pic = [[Picture alloc] init];
[pic setValuesForKeysWithDictionary:dic];
[self.arr addObject:pic];
}
}

- (void) createView {
DKFlowLayout *flowLayout = [[DKFlowLayout alloc] init];
flowLayout.columnCounts = 3;
flowLayout.columnSpace = 20;
flowLayout.rowSpace = 15;
flowLayout.edgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
flowLayout.delegate = self;

self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flowLayout];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
[self.view addSubview: self.collectionView];
[self.collectionView registerClass:[MyCell class] forCellWithReuseIdentifier:NSStringFromClass([MyCell class])];
self.collectionView.backgroundColor = [UIColor whiteColor];
}

- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.arr.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([MyCell class]) forIndexPath:indexPath];
Picture *pic = self.arr[indexPath.row];
//    [cell.picImageView sd_setImageWithURL:[NSURL URLWithString:pic.thumbURL]];
cell.pic = pic;

return cell;
}

- (CGFloat) layout:(DKFlowLayout *)layout heightForItemAtIndexPath:(NSIndexPath *)indexPath width:(CGFloat)width {
Picture *pic = self.arr[indexPath.row];
CGFloat height = pic.height.floatValue * width / pic.width.floatValue;
return height;
}

// Data.json
[
{
"thumbURL": "http://c.hiphotos.baidu.com/baike/w%3D268/sign=1396d7c49922720e7bcee5fc43ca0a3a/b3119313b07eca807f594b41902397dda044ad345982ab0b.jpg",
"width": 111.6,
"height": 180
},
...
...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: