本实例主要涉及UICollectionView和UICollectionViewFlowLayout
源码:https://github.com/ianzhengnan/WaterFall
极客学院视频地址:http://www.jikexueyuan.com/course/492.html
效果图:
开发小技巧:
对于比较长的方法名,只需记住返回值的类型,输入返回值类型和view名就可以通过xcode的提示得出想要的方法。
实现步骤如下:
1. 在ViewController.h中加入UICollectionView
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *collectionView;
@end
2. 在ViewController.m中懒加载读取图片
//lazy load
- (NSArray *)imgArr{
if(!_imgArr){
NSMutableArray *muArr = [NSMutableArray array];
for (int i = 0; i < kImgCount; i++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"huoying%d",i + 1]];
[muArr addObject:image];
}
_imgArr = muArr;
}
return _imgArr;
}
3. 在View did load方法中创建CollectionView. 注册Cell.并把它们加入到主View中。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//create collection view layout first
WaterFallFlowLayout *flowLayout = [[WaterFallFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds
collectionViewLayout:flowLayout];
self.collectionView.backgroundColor = [UIColor yellowColor];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
//register cell
[self.collectionView registerClass:[WaterFallCollectionViewCell class] forCellWithReuseIdentifier:identifier];
[self.view addSubview:self.collectionView];
}
4. 设置numberOfItemsInSection
5. 创建Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
WaterFallCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
if (!cell) {
cell = [[WaterFallCollectionViewCell alloc] init];
}
cell.image = self.imgArr[indexPath.item];
return cell;
}
6. 设置图片的新尺寸,获取edge值
// set the new size of images
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
UIImage *image = self.imgArr[indexPath.item];
float height = [self imgHeight:image.size.height width:image.size.width];
return CGSizeMake(100, height);
}
//set the margin
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
UIEdgeInsets edgeInsets = {5,5,5,5};
return edgeInsets;
}
7. 创建新类继承自UICollectionViewFlowLayout 在此类中设置CollectionView 的layout
//
// WaterFallFlowLayout.m
// WaterFall
//
// Created by zhengna on 15/6/29.
// Copyright (c) 2015年 zhengna. All rights reserved.
//
#import "WaterFallFlowLayout.h"
CGFloat const colCount = 3;
@implementation WaterFallFlowLayout
//set the layout of cell
//prepare for the setting of layout
- (void)prepareLayout{
[super prepareLayout];
_colArr = [NSMutableArray array];
_attributeDict = [NSMutableDictionary dictionary];
self.delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;
_cellCount = [self.collectionView numberOfItemsInSection:0];
if(_cellCount == 0){
return;
}
float top = 0;
for (int i = 0; i < colCount; i++) {
[_colArr addObject:[NSNumber numberWithFloat:top]];
}
for (int i = 0; i < _cellCount; i++) {
[self layoutItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
}
}
//set layout for cells
- (void)layoutItemAtIndexPath:(NSIndexPath *)indexPath{
//get the padding of cells through invoking delegate methods
UIEdgeInsets edgeInsets = [self.delegate collectionView:self.collectionView layout:self
insetForSectionAtIndex:indexPath.row];
//get the size of every items
CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
//find the minimun height
float col = 0;
float shortHeight = [[_colArr objectAtIndex:col] floatValue];
for (int i = 0; i < _colArr.count; i++) {
float height = [[_colArr objectAtIndex:i] floatValue];
if(height < shortHeight){
shortHeight = height;
col = i;
}
}
float top = [[_colArr objectAtIndex:col] floatValue];
//set the frame value of cell
CGRect frame = CGRectMake(edgeInsets.left + col * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height);
//update the height of column
[_colArr replaceObjectAtIndex:col withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]];
//save the indexPath of cell to dictronary
[_attributeDict setObject:indexPath forKey:NSStringFromCGRect(frame)];
}
- (NSArray *)indexPathsOfItem:(CGRect)rect{
NSMutableArray *array = [NSMutableArray array];
for (NSString *rectStr in _attributeDict) {
CGRect cellRect = CGRectFromString(rectStr);
//
if (CGRectIntersectsRect(cellRect, rect)) {
NSIndexPath *indexPath = _attributeDict[rectStr];
[array addObject:indexPath];
}
}
return array;
}
//get the layout info
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray * muArr = [NSMutableArray array];
//according the param of frame to calcute the which cell should be appear
NSArray *indexPaths = [self indexPathsOfItem:rect];
for (NSIndexPath *indexPath in indexPaths) {
UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexPath];
[muArr addObject:attribute];
}
return muArr;
}
//calcute the size of collection view's content
- (CGSize)collectionViewContentSize{
//get the heightest height
CGSize size = self.collectionView.frame.size;
float maxHeight = [[_colArr objectAtIndex:0] floatValue];
for (int i = 0; i < _colArr.count; i++) {
float colHeight = [[_colArr objectAtIndex:i] floatValue];
if (colHeight > maxHeight) {
maxHeight = colHeight;
}
}
size.height = maxHeight;
return size;
}
@end