iOS 自从出了UICollectionview之后,界面的样式可谓更加的多元化,对于一些较为复杂的界面UICollectionview都可以相对轻松的实现,而且由于其 FlowLayout 子类的存在,界面的布局更可谓是随心所欲,下面就来介绍下在处理图片中比较爱用到的瀑布流,我这里和一些其他人的方法不一样,我是重写了它的一个类来实现的瀑布流,那么废话不多说,直接上 Demo
首先我们需要创建一个类,基于UICollectionViewLayout 然后重写系统的协议方法
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
获取每个 item 的大小 ( 如果不重写的话 , 在当前的 .m 文件里得不到 size, 没有代理人去调用该方法得到 size)
这里为.h的代码:
@protocol myCollectionFlowLayoutDelegate <NSObject>
//重写系统的协议方法 获取每个item的大小 (如果不重写的话,在当前的.m文件里得不到size,没有代理人去调用该方法得到size)
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface myCollectionFlowlayout : UICollectionViewLayout
@property (nonatomic ,assign)id <myCollectionFlowLayoutDelegate>myCollectionFlowLayout;
@property (nonatomic ,retain)NSMutableArray *array;
@property (nonatomic ,assign)CGFloat maxHiget;
@property (nonatomic ,retain)UICollectionViewLayoutAttributes *attributes;
下面为.m 里的代码:
//重写系统prepareLayout方法,准备布局item之前会调用
- (void)prepareLayout{
[super prepareLayout];
//重新设置滚动范围时用
self.maxHiget = 0;
//用来存放item的属性
self.array = [NSMutableArray array];
//设置每列item y坐标的初始值
CGFloat LeftY = 60,MidY = 60,ReightY = 60;
//计算contentView 第一步
CGFloat maxLeft = 0,maxMid = 0 ,maxRight = 0;
//获得当前section有多少个item(由viewController的协议方法返回)
NSInteger count = [self.collectionView numberOfItemsInSection:0];
//设置每个item的属性
for (int i = 0; i < count; i++) {
//生成item下标
NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
//获取协议返回的size
CGSize itemSize = [self.myCollectionFlowLayout collectionView:self.collectionView layout:self sizeForItemAtIndexPath:index];
//判断,先把不是第一列的item取出来
if (i % 3 != 0) {
//根据item下标取出每个item属性对象,通过它能设置item的frame
self.attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
//设置默认的x坐标为0
float offsetX = 0;
if (i % 2 == 0) {
//设置中间item的x为130;
offsetX = 130;
//设置中间列item的frame
self.attributes.frame = CGRectMake(offsetX, MidY, itemSize.width, itemSize.height);
//记录中间所有item高度--->计算contentView 第二步
maxMid = MidY + itemSize.height;
//设置item中间的间距为5
MidY += itemSize.height + 5;
}else{
//设置右边item的x为255
offsetX = 255;
self.attributes.frame = CGRectMake(offsetX, ReightY, itemSize.width, itemSize.height);
maxRight = ReightY + itemSize.height;
//计算contentView 第三步
ReightY += itemSize.height + 5;
}
//
self.maxHiget = maxMid > maxRight ? maxMid +5 : maxRight + 5;
//item属性存放到数组中
[self.array addObject:self.attributes];
}else{
// //获取协议返回的size
// CGSize itemSize = [self.myCollectionFlowLayout collectionView:self.collectionView layout:self sizeForItemAtIndexPath:index];
//设置左边item属性
self.attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
//直接把左边item的X设置为5
float offsetX = 5;
self.attributes.frame = CGRectMake(offsetX, LeftY, itemSize.width, itemSize.height);
maxLeft = LeftY + itemSize.height;
LeftY += itemSize.height + 5;
self.maxHiget = self.maxHiget > LeftY ? self.maxHiget +5 : LeftY + 5;
[self.array addObject:self.attributes];
}
}
}
//重写系统方法,初始的layout的外观将由该方法返回的UICollectionViewLayoutAttributes来决定
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *Arr = [[NSMutableArray alloc]init];
for (int i = 0; i < [self.array count]; i++) {
UICollectionViewLayoutAttributes *att = [self.array objectAtIndex:i];
//判断第二个rect是不是在第一个rect的范围之内
if (CGRectIntersectsRect(rect, att.frame)) {
[Arr addObject:att];
}
}
return Arr;
}
//重新设置滚动范围ContentSize
- (CGSize)collectionViewContentSize
{
NSLog(@"===%f",self.maxHiget);
return CGSizeMake(self.collectionView.frame.size.width, self.maxHiget);
}
到这里,瀑布流里最为关键的我们已经完成了,接下来就是在 Colltroller 里来调用我们重写的类
创建一个 viewColltroller
.h 里的代码:
#import "myCollectionFlowlayout.h"
@interface ViewController : UIViewController<myCollectionFlowLayoutDelegate,UICollectionViewDataSource,UICollectionViewDelegate>
@property (nonatomic ,retain)NSMutableArray *allArr;
@property (nonatomic ,retain)UICollectionView *colletionView;
@end
.m 里的代码:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
myCollectionFlowlayout *flowLayout = [[myCollectionFlowlayout alloc]init];
flowLayout.myCollectionFlowLayout = self;
self.allArr = [NSMutableArray array];
self.colletionView = [[UICollectionView alloc]initWithFrame:[[UIScreen mainScreen]bounds] collectionViewLayout:flowLayout];
self.colletionView.delegate = self;
self.colletionView.dataSource = self;
[self.view addSubview:self.colletionView];
self.colletionView.backgroundColor = [UIColor blackColor];
[self.colletionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"reuse"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
NSLog(@"1111111111111");
return 100;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = @"reuse";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithRed:1.000 green:0.677 blue:0.555 alpha:1.000];
if (indexPath.row % 2 == 0 && indexPath.row % 3 != 0) {
cell.backgroundColor = [UIColor colorWithRed:1.000 green:0.522 blue:0.625 alpha:1.000];
}else if (indexPath.row % 3 == 0){
cell.backgroundColor = [UIColor colorWithRed:0.944 green:1.000 blue:0.603 alpha:1.000];
}
return cell;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(375/3 - 10, arc4random() % 201 + 160);
}