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 alloc] initWithFrame:self.bounds];
[self.contentView addSubview:_imageView];
_numberLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 20)];
[_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中的x、y
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];
//求每列的宽度,也就是每个item的width
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];
//上一次总的列高 加上 行高 加上新加上的item的height,才是现在这一列的总高度
//minHeight为最小列现在的高度
//lineHeight为行间距
//height为新加的item的高
_columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];
//重新算最小列高的下标
minHeightIndex = [self indexOfMinHeight];
//算下一次新加的item的x和y值
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上。