瀑布流
瀑布流的效果就不介绍。直接百度。。。
UICollectionView 是一个强大类似 UITableView 的显示视图,(可能我的理解不是很正确,但可以显示集合数据应该没错)。
瀑布流实现思路,有多列,计算每列高度,将单元格数据追加在短的一列上。
以下使用 UICollectionView 来实现瀑布流。
项目源码
- 准备过程
#import "ViewController.h"
#import "MyLayout.h"
#import "ImageModel.h"
#import "MyCell.h"
@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
{
UICollectionView *_collectionView; // 集合视图
NSMutableArray *_cellDataArray; // 所有单元格数组对象
NSMutableData *_data; // 网络数据
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadData];
[self createCollectionView];
}
#pragma mark - Data
- (void)loadData
{
// 初始化对象
_cellDataArray = [[NSMutableArray alloc] init];
_data = [[NSMutableData alloc] init];
// 测试数据
for ( int i = 0 ; i < 20 ; i++ )
{
ImageModel *model = [[ImageModel alloc] init];
model.cellHeight = arc4random()%300 + 50;
[_cellDataArray addObject:model];
}
} // 加载数据
#pragma mark - View
- (void)createCollectionView
{
// 创建布局对象,需要对显示图片的布局进行调整所有传递给布局对象
MyLayout *layout = [[MyLayout alloc] init];
layout.cellDataArray = _cellDataArray;
// layout 决定来 collectionView 中所有 cell (单元格) 的布局
_collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
_collectionView.dataSource = self;
_collectionView.delegate = self;
// 创建 集合视图单元格 ,放在重用队列里面
[_collectionView registerClass:[MyCell class] forCellWithReuseIdentifier:@"cellid"];
_collectionView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_collectionView];
} // 创建集合视图
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _cellDataArray.count;
} // 单元格总个数
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 重用队列中获取单元格
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath];
[cell fillCellData:_cellDataArray[indexPath.row]];
return cell;
} // 所有单元格
@end
- 三个辅助类
- 布局类,每一个单元格都需要根据高度进行布局,将高度较小的追加在短的一边
- 单元格类, 用于显示数据的单元格
- 数据模型类,保存数据
#import <UIKit/UIKit.h>
// 布局类
@interface MyLayout : UICollectionViewLayout
@property (nonatomic, strong) NSMutableArray *cellDataArray; // 所有对象数组,
@end
#import "MyLayout.h"
#import "ImageModel.h"
@implementation MyLayout
/**
* 集合视图布局有三个方法必须实现
*/
- (CGSize)collectionViewContentSize
{
/**
* 思路:需要确定是左右两边视图高度,哪一个高,将单元格视图追加在高度较小的一边。
*/
CGFloat leftHeight = 0.0;
CGFloat rightHeight = 0.0;
for ( int i = 0 ; i < _cellDataArray.count ; i++)
{
CGFloat h = [_cellDataArray[i] cellHeight];
if (leftHeight <= rightHeight) // 将左右单元格高度分开
{
leftHeight += h;
}
else
{
rightHeight += h;
}
}
return CGSizeMake(0, leftHeight > rightHeight ? leftHeight : rightHeight);
} // 返回 collectionView 的内容的大小,用于显示
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
/**
* 需要循环调用每一个单元格的属性方法,用于设置
*/
NSMutableArray *array = [[NSMutableArray alloc] init];
// 这里只有一个段,段属性和 UITableView 类似
for ( int i = 0 ; i < [self.collectionView numberOfItemsInSection:0] ; i++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[array addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
return array;
} // 返回包含所有 cell 的属性的数组
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
// 两个属性
// 单元格大小
CGFloat cellHeight = [_cellDataArray[indexPath.row] cellHeight];
attr.size = CGSizeMake(160, cellHeight);
// 单元格位置
CGFloat leftHeight = 0.0;
CGFloat rightHeight = 0.0;
for ( int i = 0 ; i < indexPath.row ; i++ )
{
CGFloat h = [_cellDataArray[i] cellHeight];
if (leftHeight <= rightHeight)
{
leftHeight += h;
}
else
{
rightHeight += h;
}
}
if (leftHeight <= rightHeight)
{
attr.center = CGPointMake( 80, leftHeight + cellHeight / 2 );
}
else
{
attr.center = CGPointMake( 240, rightHeight + cellHeight / 2 );
}
return attr;
} // 返回每一个 cell 对应的属性
@end
#import <UIKit/UIKit.h>
@class ImageModel;
@interface MyCell : UICollectionViewCell
/**
* 填充单元格数据
*
* @param model 图片模型
*/
- (void)fillCellData:(ImageModel *)model;
@end
#import "MyCell.h"
#import "ImageModel.h"
@implementation MyCell
{
UIImageView *_imgView;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
_imgView = [[UIImageView alloc] init];
[self.contentView addSubview:_imgView];
}
return self;
}
- (void)fillCellData:(ImageModel *)model
{
_imgView.frame = CGRectMake(5, 5, 150, self.contentView.bounds.size.height - 10);
_imgView.backgroundColor = [UIColor colorWithRed:(arc4random() % 10 * 0.1) green:(arc4random() % 10 * 0.1) blue:(arc4random() % 10 * 0.1) alpha:0.5];
}
@end
#import <Foundation/Foundation.h>
// 数据模型
@interface ImageModel : NSObject
@property (nonatomic,copy) NSString *imgUrl; // 图片网络路径
@property (nonatomic,assign) CGFloat imgHeight; // 图片高度
@property (nonatomic,assign) CGFloat imgWidth; // 图片宽度
@property (nonatomic,assign) CGFloat cellHeight; // 单元格高度
@end
- 页面效果
加载网络数据
布局方法不需要修改,修改数据填充方法
使用SDWebImage开源库
-(void)fillData:(ImageModel *)model
{
_imgv.frame = CGRectMake(5, 5, 150, self.contentView.bounds.size.height - 10);
_imgv.backgroundColor = [UIColor colorWithRed:(arc4random() % 8)*0.1 green:(arc4random() % 8)*0.1 blue:(arc4random() % 8)*0.1 alpha:1];
[_imgv setImageWithURL:[NSURL URLWithString:model.imgUrl]];
}
获取网络数据的具体实现有很多种办法,这里就不给出了。
我已上传源代码
http://download.csdn.net/detail/a274275605/8120707