iOS使用CollectionView实现瀑布流
2016-03-16 09:27
351 查看
瀑布流的原理
将屏幕等分成三列 然后将图片加载到每一列中,在加入到列之前,首先判断那一列的高度最低,然后把图片加到高度最低的那列中。瀑布流设计思路分析
使用UICollectionView,采用自定义布局的方式,设置cell的排列规则 完成瀑布流。自定义布局中,指定滚动方向,默认列数,行间距,列间距,以及指定cell的大小itemSize
创建一个数组columnMaxYs(记录当前每一列的最大Y值)
通过判断记录的最大Y值是否为最小的一列 计算item的X坐标 和Y坐标 并记录添加上的item那一列的最大Y坐标 设置item的frame属性
当我们的item进入复用池的时候,我们的界面展示的我们眼睛看到的以及我们想的,是和事实不相符的。 当我们向上滑动的时候你感觉 Y值在无线变大,但其实我们的Y值在最上方还是0。这里就需要用到prepareLayout方法。这个方法会在item出现在屏幕上之前反复执行。
在第一次加载的时候我们会计算所有的item的布局属性,但是当我们上下滑动的时候,还是需要重新计算这些布局属性,所以我们需要提供一个布局属性数组存放Cell的布局属性,避免必要的计算。
我们需要知道如何返回我们计算出来的item的布局属性,并且在那里计算合适,不会出现数据丢失的现行, layoutAttributesForElementsInRect:(返回所有元素的布局属性数组)。
这里需要设置Collection的滚动属性 ,就需要设置她的ContentSize 。没关系系统已经给出了这样的方法collectionViewContentSize
瀑布流的基本实现代码
#import <UIKit/UIKit.h> @interface ZQCollectionViewController : UICollectionViewController @end
#import "ZQCollectionViewController.h" #import "ZQCollectionViewCell.h" #import "ZQCollectionViewLayout.h" @interface ZQCollectionViewController () { NSMutableArray *arr; } @end @implementation ZQCollectionViewController static NSString * const reuseIdentifier = @"Cell"; - (void)viewDidLoad { [super viewDidLoad]; arr=[NSMutableArray array]; for (int i=0; i<49; i++) { NSString *string=[NSString stringWithFormat:@"%d.jpg",i%5+1]; [arr addObject:string]; } ZQCollectionViewLayout *layout=[[ZQCollectionViewLayout alloc]init]; layout.imageList=arr; self.collectionView.collectionViewLayout=layout; [self.collectionView registerNib:[UINib nibWithNibName:@"ZQCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:reuseIdentifier]; } - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return arr.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ZQCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; cell.imgV.image =[UIImage imageNamed:arr[indexPath.row]]; cell.backgroundColor = [UIColor purpleColor]; return cell; } @end
#import <UIKit/UIKit.h> @interface ZQCollectionViewCell : UICollectionViewCell //注意这里是使用XIB绘制的 @property (weak, nonatomic) IBOutlet UIImageView *imgV; @end
#import "ZQCollectionViewCell.h" @implementation ZQCollectionViewCell @end
#import <UIKit/UIKit.h> @interface ZQCollectionViewLayout : UICollectionViewLayout @property(nonatomic,copy)NSArray *imageList; @end
#import "ZQCollectionViewLayout.h" #define NewDefaultCollectionViewWidth self.collectionView.frame.size.width //static 只在当前作用域使用 const 不可修改的 static const UIEdgeInsets NewDefaultInsets={10,10,10,10}; //定义行列之间的间距 static const CGFloat NewDefaultColumn=10; //定义默认的列数 static int NewDeraultNumber=3; @interface ZQCollectionViewLayout () //创建数组存放 Y值最大值 存放cell的布局属性 @property(nonatomic,strong)NSMutableArray *columnArr; @property(nonatomic,strong)NSMutableArray *cellArr; @end @implementation ZQCollectionViewLayout - (NSMutableArray *)columnArr{ if (!_columnArr) { _columnArr=[NSMutableArray array]; } return _columnArr; } - (NSMutableArray *)cellArr{ if (!_cellArr) { _cellArr =[NSMutableArray array]; } return _cellArr; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewLayoutAttributes *attr=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; //布局属性刷新更改 //获取总的横向间距 CGFloat xMARGIN=NewDefaultInsets.left+NewDefaultInsets.right+(NewDeraultNumber-1)*NewDefaultColumn; CGFloat width=(NewDefaultCollectionViewWidth-xMARGIN)/NewDeraultNumber; #pragma mark -- 这里返回图片的高度 UIImage *image=[UIImage imageNamed:self.imageList[indexPath.row]]; CGFloat height=image.size.height *(width/image.size.width); #pragma mark -- 这里我们需要获取x坐标的值 如何获取 因为我们要做的是将需要展示的数组按顺序向下排列 而顺序就将后进来的插入到 最短的那一列 所以要获取这个x坐标我们就需要找出这个最小的y坐标才能确定 NSInteger sum=0; #pragma mark -- 下面这个遍历为什么要使用也是上面的原因 取出最大的y值 并获取对应的列数 其实columnArr只有三个元素 CGFloat sumMaxY=[self.columnArr[0] doubleValue]; for (int i=0; i<self.columnArr.count; i++) { CGFloat anyMaxY=[self.columnArr[i]doubleValue]; if (sumMaxY>anyMaxY) { sumMaxY=anyMaxY; sum=i; } } CGFloat x=NewDefaultInsets.left +sum*(width+NewDefaultColumn); CGFloat y=NewDefaultInsets.top+sumMaxY; attr.frame=CGRectMake(x, y, width, height); //更新数组,获取最大的Y 下一次比较时用到 记住每一次都会走下面这个方法 而这个方法 第一次的时候都是0 第二次的时候两个0 第三次的时候就不一样了 self.columnArr[sum]=@(CGRectGetMaxY(attr.frame)); return attr; } #pragma mark -- 这里下面的方法 是当我们向上或向下滑动item的时候 我们需要将我们的最大Y坐标重置 为什么呢 因为如果你继续使用最大Y坐标 它还是向下排列 - (void)prepareLayout{ [super prepareLayout]; //设置cell的最大Y值 [self.columnArr removeAllObjects]; for (int i=0; i<NewDeraultNumber; i++) { //这里使用下面的方法是给最大值一个初始值 [self.columnArr addObject:@(NewDefaultInsets.top)]; } //设置cell的布局属性 这里的self.layoutAttributesForItemAtIndexPath 是本类的一个属性 通过对应的indexPath我们可以拿到对应的item的布局属性 然后存储起来 [self.cellArr removeAllObjects]; NSInteger count=[self.collectionView numberOfItemsInSection:0]; for (int i=0; i<count; i++) { NSIndexPath *indexPath=[NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attrs=[self layoutAttributesForItemAtIndexPath:indexPath]; [self.cellArr addObject:attrs]; } } #pragma mark -- 设置collectionView的范围 contentSize - (CGSize)collectionViewContentSize{ CGFloat sumMaxY=[self.columnArr[0] doubleValue]; for (int i=0; i<self.columnArr.count; i++) { CGFloat anyMaxY=[self.columnArr[i]doubleValue]; if (sumMaxY>anyMaxY) { sumMaxY=anyMaxY; } } //这里返回的横坐标是什么都可以 return CGSizeMake(0, sumMaxY); } - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{ //在里我们将我们存储起来的item布局属性交付给cell return self.cellArr; } @end
相关文章推荐
- 在写一个iOS应用之前必须做的7件事(附相关资源)
- 详解在iOS App中自定义和隐藏状态栏的方法
- iOS报错笔记
- iOS开发笔记13:顶部标签式导航栏及下拉分类菜单
- IOS开发之 一个实例解析 录音
- iOS开发之 音频播放
- iOS---cell-自适应高度
- iOS 页面跳转传值,属性传值,代理传值,代码块传值,单例传值,通知传值
- IOS GCD 浅析
- iOS开发中的CALayer精析
- iOS支付那些事(二)支付宝
- IOS SOCKET编程
- iOS view的frame和bounds之区别(位置和大小)
- 1.开源项目NSString + CALRegular
- iOS企业开发者计划付费后的坑
- 如何设计一个 iOS 控件?(iOS 控件完全解析)
- iOS 图像裁剪圆角的几张方法
- iOS 终端常用命令
- 记录一下iOS开发中琐碎的点点_1
- IOS导航栏颜色渐变与惯用属性