瀑布流的简便完成方式,自定义collocationViewLayo

瀑布流已经是前几日很常用的布局样式,用collectionView就足以很平价的贯彻,以后github上star最多的正是以此C摩Toro拉ollectionViewWaterfallLayout,也是自己项目中时常用的。时间长了或然察觉有满足不断要求的地方(例如始终缺点和失误的像tableViewHeader同样的collectionViewHeader和collectionViewFooter),还发掘了个bug:当section个数大于1但先是个section中item个数为0时,第二个section中item的地方会现出谬误(原因是当item==0时依旧减去了itemSpacing,给她提了issue,但是没管理)再加上其Swift版的库一贯没更新,所以照旧决定本人仿写一个,学习一下大神的思绪,顺便修复开采的bug,加上自个儿索要的header和footer,整理下代码结构。地址在此间:

序言

达成瀑布流简单,完结分区瀑布流,並且每一个区的瀑布流的列数不一致样且有区头和区尾,就不是太轻巧了。小编嫌麻烦不甘于本身写(——>笔者承认懒,不乐意动脑子 *V*)开首在网络找了非常多,都以仅仅三个区的瀑布流,没区头和区尾,完全满意不断小编的须要。不能,产品的急需在那,无法不做吗,于是自身静下心来开头写。

前言

图片 1

那二日开采的时候,必要在tableView上拉的时候完结最上面包车型大巴cell随着滑动从侧面移动出来的功用(Taobao顾客端在上拉加载的时候从侧边滑动现身的功力)。苦思了相当久,最终通过在scrollView的代办中通过剖断偏移量来改动方今最下边包车型客车cell的frame完成这种成效,但是这么的贯彻却远远达不到作者想要的靶子。同期,在滑动tableView时进行大量繁杂的计量还致使了上拉时轻微卡顿的光景,于是笔者导出寻觅另外的缓和方案。终于,被作者不经意了非常久的UICollectionView成为了消除这一标题标最棒选项。

其代理方法和总体性模仿UICollectionViewFlowLayout 所写,使用办法和UICollectionViewFlowLayout类似

超简单的瀑布流达成,这里说一下小编的笔触,详尽代码在这里。

CBlackBerryollectionViewWaterfallLayout的差非常的少思路是:每一种section有多少个column是一定的,然后依照insect,spacing等品质,就能够总计出每一列的增进率,然后依照delegate重回的itemSize,就可以按比例缩放出实际展现的itemSize。然后依照renderDirection属性,分明各个item的职位。C中兴ollectionView沃特erfallLayout想做二个跟UICollectionViewFlowLayout同样不难易用的类,所以整个结构就是仿照UICollectionViewFlowLayout来的,属性名称,公约名称等也是,所以看起来拾贰分称心快意。

关于UICollectionView

意义描述:

功用演示

图片 2

UICollectionView在iOS6从此第一回被引进,它和tableView分享一套API设计,可是意义却远比tableView庞大,其最大的风味在于健全的灵活性和可定制化。它对于子视图展现的长河来说只是扮演了容器的指标,它不在乎子视图内的确的源委。由于它将调控子视图地点、大小以及外观等性情的任务委托给单独的一个搭架子对象(UICollectionViewLayout),我们得以经过连续这么些布局类来落到实处自定义化的collectionView。

1 > 满意UICollectionViewFlowLayout提供的一般性的线性布局和网格布局

图片 3

跟UICollectionViewDelegateFlowLayout大概同样,可是sizeForItem产生了required,referenceSize变成了height。referenceSize变成height笔者认为很客观,因为实际用经过中也只会用到height,width肯定是collectionView的宽度;sizeForItem笔者觉着能够毫不非得,若无安装,那依据总计出来的columnWidth设置成星型就行了嘛,就像是UICollectionViewFlowLayout同样也会有个早先值。

图片 4

2> 满足单区和多区的瀑布流布局。

完成思路

图片 5

由此上海教室,大家得以看来UICollectionView分裂于tableView的贰个特性是前面三个每四个item而不是单独的一行,官方文书档案中说起

3> 满意多区瀑布流时每一个区的列数能够区别

collectionView能落成各中吊炸天的布局,其精髓就在于UICollectionViewLayout,由此我们要自定义多少个layout来继续系统的UICollectionViewLayout,全部工作都在这么些类中展开。

也跟UICollectionViewDelegateFlowLayout差不离同样,多了个columnCount,多了个itemRenderDirection,referenceSize变成了height,还多了minimumContentHeight和三个帮衬方法。没啥好深入分析的。

During layout, the flow layout object adds items to the current line until there is not enough space left to fit an entire item.

4> 知足设置header和footer

1.定义所需属性

图片 6

在把新的item增加到近期行上的时候,flowLayout对象会计算当前行上剩下的肥瘦是或不是足以容纳下那个item,假诺不能包容,那么就换行。越多关于collectionViewLayout性子能够查阅那篇文章。

5> 满意设置header和footer的距离

瀑布流的笔触便是,从上往下,那一列最短,就把下二个item放在哪一列,由此大家要求定义一个字典来记录每一列的最大y值

研讨是承继UICollectionViewDelegate的,所以layout的delegate是取self.collectionView.delegate作为layout的delegate,用起来跟UICollectionViewFlowLayout完全一致,舒服~columnHeights是个二维数组,保存每种section中每一个column的可观,注意是有血有肉某一列的一起高度,不是有个别cell或许item的万丈!!!这一个相当重大unionRects是个相比难精通的事物,我用它来优化layoutAttributesForElementsInRect这几个格局,我个人认为意义非常小。。。或然是没通晓到作者的暗意吧。。。headerAttribute和footerAttribute小编用了字典并不是二维数组,key是应和的section。别的属性也都很好驾驭,不说了。

对于自定义collectionView来说,瀑布流大概是独占鳌头基本的自定义方案。因而,大家前日的事例将从定制瀑布流起初。苹果官方文书档案对于UICollectionViewLayout的选拔有以下表明:

只顾:本文不关乎到装修视图的相关代理方法以及总结。

每一个item都有一个attributes,由此定义叁个数组来保存每一个item的attributes。

最重大的正是以此prepareLayout那么些主意。最起首发轫化种种数组,然后开首遍历section总计有所的layoutAttributes。1, 首先是sectionHeader,C华为ollectionViewWaterfallLayout是让sectionHeader也受sectionInset影响的,所以sectionHeader的最初x是sectionInset.left, 起头y是sectionInset.top;而UICollectionViewFlowLayout的sectionHeader是不受sectionInset影响的,所以最初x是0,起先y也是0;三种办法都有有道理,小编更赞成于UICollectionViewFlowLayout的不二等秘书籍,因为section大小给大了,view可以用空白填补,不过要给小了想设置不用样式就难了,所以作者仿写的时候就就用UICollectionViewFlowLayout的办法了。

You can configure the flow layout either programmatically or using Interface Builder in Xcode. The steps for configuring the flow layout are as follows:

先是要知道的事务:collectionView与collocationViewLayout的涉及。

小编们还非得精晓有多少列以及列间距、行间距、section到collectionView的边距。

2, 然后是将columnHeights中对应section的数组的值全部设置为sectionHeader.fame.maxY。这一步是为了统一下边总括item地点的序幕地方。小编以为,既然是columnHeights,就无须把sectionHeader之类的万丈也算算进去了,所以仿写的时候使用了另外的持筹握算办法:用二个民用变量contentHeight来保存当前的Y值,columnHeights只用来保存对应的column的可观,总结地点的时候将双方加起来就能够

1、Create a flow layout object and assign it to your collection view.

collocationView肩负呈现,collectionviewLayout担任提供怎么样彰显,蕴涵cell的高低地点,header和footer的大小地点等,UICollectionViewFlowLayout 承继自UICollectionViewLayout是苹果公司包装好的layout,可以达成轻便的网格和线性布局,当cell的大大小小和距离同样时方可用UICollectionViewFlowLayout,如若要贯彻相比复杂的布局,就供给自定义了。

图片 7

3, 然后是测算每种item的任务先总计出item应该献身那一列,CNokiaollectionViewWaterfallLayout用itemRenderDirection定义了两种排列格局:最短优先,从左往右,从右往左;笔者认为用处不是相当的大,既然是瀑布流了,那应该不太在意横着是怎么拍的,所以仿写的时候就只保留了最短优先这一种办法;而规定哪些最短的点子也很简短,便是从columnHeights中寻找最短的那一列的index;然后创设attribute,根据indexPath设置frame,增多到数组就能够也便是此处,CNokiaollectionViewWaterfallLayout有个bug:假使某些section的item个数为0,那就不应有计算item的职责,而C金立ollectionViewWaterfallLayout近日的做法是在总结实现未来,判别columnHeights对应section的columnCount是还是不是为0,为0则再减去itemSpacing,难点是有些section的columnCount跟itemCount其实没啥关系,或许本人陈设那几个section有2列,可是恰恰非常少,itemCount为0,这种处境下决断就出错了。。。作者仿写的做法是:把加spacing放在加item中度在此以前;首先推断item是不是是该列的率先个,是率先个则不用加spacing,否则再加spacing;这段日子来看是很好的化解了这一个主题素材~~

2、Configure the width and height of cells.

其次,要领悟UICollectionViewLayoutAttributes 类的习性,以下是每二个cell的个性,都以透过UICollectionViewLayoutAttributes属性呈现出来的。

//总列数

4, 然后是sectionFooter,方法同sectionHeader。

3、Set the spacing options (as needed) for the lines and items.

CGRect frame; // cell的尺寸已经x,y值

@property (nonatomic, assign) NSInteger columnCount;

到那边实在整个布局所供给的性质就都早已总括出来了,上面只需求按必要重载UICollectionViewLayout的函数,再次来到对应数据就能够。这里C金立ollectionViewWaterfallLayout用了二个unionRect数据,貌似是用来优化总结:写死了unionSize

20,然后将装有的item分为几组,每组18个,总计出每组的unionRect,保存在数组中。

接下来是索要重载的函数- collectionViewContentSize;``- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path;``- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;如上那多少个依据下边包车型地铁猜度重返就可以;- shouldInvalidateLayoutForBoundsChange:newBounds;本条方式一般都以判定新旧bounds是还是不是一样,同样则赶回NO,不雷同再次回到YES。- (NSArray *)layoutAttributesForElementsInRect:rect;是要求潜心的,C索爱ollectionViewWaterfallLayout也正是在那边运用了特别unionRects数组,前后七个遍历寻觅具备与rect想交的rect,再回去须要的item的attributes这里也是本人最不驾驭的地方,认为那几个点子对功用的升迁很轻易呐,反正小编仿写的时候是一向遍历全部attributes数组,重返与rect相交的数组了。有精晓作者那么写有何深意的,望不吝赐教~~~

1,完全都以用Swift3.0写的,语法什么的应当都以新型的,没什么包容性难题2,参与了 collectionViewHeaderHeight和collectionViewFooterHeight四个属性,用法同sectionHeader和sectionFooter,供给在collectionView注册nib或然class,然后在- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;方法中抽取来设置就可以这里因为collectionView的布局完全受layout调控,所以像tableView同样平昔设置为collectionView的质量是可怜的,确定会涉及到layout,最近只想到了这种办法,要是什么人有怎样好的想法,款待探讨~3,到场了私下认可的itemSize达成全体的议和章程默许都能够不达成,不兑现的时候,就一定是八个各样section固定有几列,且援助collectionViewHeader和collectionViewFooter的layout4,自认为代码写的还算相比较正式,结构还算清晰,看起来比较舒服(⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄)

4、If you want section headers or section footers, specify their size.

CGPoint center;//cell的中央点

//列间距

5、Set the scroll direction for the layout.

CGSize size;// cell的size

@property (nonatomic, assign) NSInteger columnSpacing;

忽略是由此创造UICollectionViewLayout对象来创造大家的collectionView,然后配置cell的尺码、间距行距等,有不可或缺的时候还能够对组头组尾视图实行安装。

CATransform3D transform3D;// cell的3D旋转

//行间距

UICollectionViewLayout

CGRect bounds NS_AVAILABLE_IOS;

@property (nonatomic, assign) NSInteger rowSpacing;

在学习怎么自定义以前,大家必要驾驭一下UICollectionView中不一样类的依赖关系

CGAffineTransform transform NS_AVAILABLE_IOS; // cell 的旋转

//section到collectionView的边距

图片 8

CGFloat alpha;//alp值

@property (nonatomic, assign) UIEdgeInsets sectionInset;

在体现cell的时候,collectionView会向UICollectionViewLayout询问布局属性。那时候,大家得以经过重载方法创设UICollectionViewLayoutAttributes对象,各个对象保存一个item的布局属性。接下来,大家会因此创立UICollectionViewFlowLayout的子类来兑现瀑布流,之所以采用这么些类的缘故在于它的定制要比定制承接自UICollectionViewLayout的子类简单,因为它总结了itemSize、minimumLineSpacing等主要的布局属性。

NSInteger zIndex; // default is 0 //z轴

//保存每一列最大y值的数组

瀑布流最大的性情在于区别尺寸的cell之间打开严密的缝合连接,可是只要大家使用的是暗中同意的布局对象,那么展现的效应就能够跟上面包车型地铁图一律不堪入目:

getter=isHidden) BOOL hidden; // As an optimization,

@property (nonatomic, strong) NSMutableDictionary *maxYDic;

图片 9

还会有,要领悟UICollectionViewLayout的多少个艺术:

//保存每三个item的attributes的数组

大家能够见见,系统总结下一行行高的时候是基于当前行业中y坐标和中度和的最大值加上行距正是下一行的y坐标开始点 nextLineY = MAX(cell.y cell.height) lineSpacing。所以大家想要实现瀑布流的做法就是透过保留每一列当前的可观,然后用来修改这一列上下二个item的苗头坐标来落到实处每八个cell之间紧密缝合的作用。

1, prepareLayout :是特意用来计划布局的,在prepareLayout方法里面大家能够事先就总结前面要用到的布局消息并蕴藏起来,幸免前面方法数次乘除,升高质量。譬如,大家得以在此办法就总计好每一个cell的习性、整个CollectionView的剧情尺寸等等。此方式在布局在此之前会调用二次,之后独有在调用invalidateLayout、shouldInvalidateLayoutForBoundsChange:重临YES和UICollectionView刷新的时候才会调用。

@property (nonatomic, strong) NSMutableArray *attributesArray;

图片 10

2,- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 重临对应的indexPath的cell的attributes

2.重写系统方法

连带方法

3- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath 再次来到对应的header和footer的attributes

笔者们总共须要重写4个格局

系统在预备对item进行布局前会调用那么些措施,大家重写那个措施之后能够在点子里面预先安装好内需利用的变量属性等。比如在瀑布流开头布局前,我们能够对存储瀑布流中度的数组举办伊始化。不时大家还索要将布局属性对象进行仓库储存,比如纸牌动画式的定制,也足以在那几个主意里面实行最早化数组。切记要调用[super prepareLayout];

4 - collectionViewContentSize ;collectionView的size 那一个size不是可视范围的size是整整collectionView的size

1)- (void)prepareLayout

鉴于collectionView将item的布局职分委会托给layout对象,那么滚动区域的大大小小对于它来说是不可见的。自定义的布局对象必得在这一个法子里面计算出显示内容的深浅,富含supplementaryView和decorationView在内。

5 - (NSArray *)layoutAttributesForElementsInRect:rect 重临在rect范围内装有cell footer和head的attribute

2)- (CGSize)collectionViewContentSize

村办以为实现定制布局最基本的措施,未有之一。collectionView调用这些情势并将笔者坐标类别中的矩形传过来,那个矩形代表着近期collectionView可视的限制。大家必要在这么些办法里面再次来到四个席卷UICollectionViewLayoutAttributes对象的数组,这么些布局属性对象说了算了前段时间呈现的item的高低、档期的顺序、可视属性在内的布局属性。同期,那些艺术还是能安装supplementaryView和decorationView的布局属性。合理利用那么些方式的前提是毫不随意重返全数的天性,除非这几个view处在日前collectionView的可视范围内,又或许大批量外加的计量形成的顾客体验下落——你加班的来头。

打探以上的几点就能够起来图谋了。计算的相继是从上到下,即从区头到每个区的cell再到区尾

3)- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

一定首要的格局。collectionView大概会为了一点特殊的item必要例外的布局属性,我们能够在那一个办法中开创而且再次来到极其定制的布局属性。依照传入的indexPath调用[UICollectionViewLayoutAttributes layoutAttributesWithIndexPath: ]方式来创立属性对象,然后设置创制好的习性,包含定制形变、位移等卡通效果在内

设置有个别数组用于存储总计好的值:如下

4)- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

当collectionView的bounds改换的时候,大家供给报告collectionView是或不是须求重新总计布局属性,通过那一个点子重回是不是要求再行总括的结果。轻便的归来YES会导致我们的布局在每一秒都在拓宽持续的重绘布局,产生额外的乘除职分。

//存放attribute的数组

- (void)prepareLayout 方法

居安思危干活

@property (nonatomic, strong) NSMutableArray *attrsArray;

布局前的一部分计划干活都在此地举办,最早化字典,有几列就有几个键值对,key为第几列,value为列的最大y值,初步值为上内边距:

开荒Xcode创制三个新类型,命名称为名字前缀 沃特erFlow德姆o。创造好项目然后,接纳ViewController.h,然后修改父类为UICollectionViewController

//贮存当前区中相继列的当下的可观

for (int i = 0; i < self.columnCount; i ) {

图片 11

@property (nonatomic, strong) NSMutableArray *columnHeights;

self.maxYDic[@(i)] = @(self.sectionInset.top);

开荒Main故事板,然后删除已经存在的ViewController,显示右边控件栏拉进来多少个UICollectionViewController。然后选中新增添进来的调节器,设置为传说板的初叶化调控器。

//collectionView的Content的高度

}

图片 12

@property (nonatomic, assign) CGFloat contentHeight;

成立每种item的attributes,并存入数组:

接下来command N新建文件,选取父类为UICollectionViewFlowLayout,命名叫WaterFlowLayout,创造布局类。接着,在传说板的调整器里面接纳collectionView的布局对象。在起初重写方法达成瀑布流从前,大家要驰念好瀑布流的落到实处思路:

//记录各类区最高的

//依据collectionView获取总共有微微个item

图片 13

@property (nonatomic, assign) CGFloat lastContentHeight;

NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];

第一,由于瀑布流的item尺寸长度宽度不定,寻常来说分为等宽、等高三种(ps:就算不等宽也不等高,先不说代码上贯彻起来的复杂程度,单单是视觉上就比不上格了)。每个item都是紧密连接的,由此大家需求叁个容器来囤积每一列/行业前的最大长/宽值。这里大家将采纳二个囤积分歧列高度的数组来兑现。

//每一个区的区头和上个区的区尾的离开

//为每二个item制造三个attributes并存入数组

其次,每二个item的尺码在率先次呈现的时候就应当分明好。纵然瀑布流的尺码是私行的(实际采取中时时是由图片尺寸决定的),然则大家并不愿意在下拉出一大截地点后回头滚动回来的时候,这么些item的尺码再度发生变化。那不符合逻辑,也会变成人中学度计算上的巨大偏差。所以大家还索要把这几个坐标尺寸存储起来,并和item对应的indexPath成对存款和储蓄。因而大家用NSStringFromCGRect()方法将item的岗位音信变换来字符串后和indexPath成对存款和储蓄在字典中,何况由于frame恐怕会油可是生一样值,所以我们将frame转变来字符串存款和储蓄并让indexPath作为key。

@property (nonatomic, assign) CGFloat spacingWithLastSection;

for (int i = 0; i < itemCount; i ) {

综述上边的缅想,大家的layout类个中应该富含多个成员属性

先是是重写 prepareLayout方法,也是最重要的一步。在此方法中形成初步化。全部的持筹握算都置为零。

UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];

@property (nonatomic, strong) NSMutableDictionary * attributes;

第一步:通过 [self.collectionView numberOfSections] 方法获得collectionView中一共有多少个区。设置一个for循环。

[self.attributesArray addObject:attributes];

@property (nonatomic, strong) NSMutableArray * colArray;

第二步:通过 - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath 获取各类header的习性。总结完毕未来把attributes增添到attrsArray 数组中 ,同有时候还应该有根据sectionInsets 等参数更动contentHeight 的惊人

}

除此而外,我们还须要多少个宏定义来表示包蕴item间距、行距、列数以及每三个item的肥瘦:

其三步: 设置区头完成未来,在循环中依照 [self.collectionView numberOfItemsInSection:i] 获取相应的区有个别许个cell

- (CGSize)collectionViewContentSize 方法

#define COLUMNCOUNT 3

在这一步中总括是最麻烦的。可以分为如下步骤:

用来计量collectionView的contentSize

#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width

1> 计算每一个cell的frame。 依据此区中计算有几列和荧屏的宽窄,以及种种cell的之间的间距,总计出各种cell的肥瘦,因为中度是外面传过来的,所以中度无需总结。那么还索要精晓cell的x值和y值。

相似瀑布流只可以垂直滚动,不能够水平滚动,因而contentSize.width = 0,大家只必要计算contentSize.height就可以

#define INTERITEMSPACING 10.0f

x值:首先抽出当前区的中哪一列最低。

从字典中找寻最长列的最大y值,再加多上面包车型客车内边距,即为contentSize.height

#define LINESPACING 10.0f 10.0f

NSInteger tempMinColumn = 0; //默认第 0 列最小

- (CGSize)collectionViewContentSize {

#define ITEMWIDTH (SCREENWIDTH - (COLUMNCOUNT - 1)*INTERITEMSPACING) / 3

CGFloat minColumnHeight = [self.columnHeights[0] doubleValue]; // 抽出最小的那一列的惊人

//假诺第0列是最长的那列

代码实现

for (NSInteger i = 0; i < self.columnCount; i ) {

__block NSNumber *maxIndex = @0;

/**

CGFloat columnH = [self.columnHeights[i] doubleValue];

//遍历字典,搜索最长的那一列

准备布局item前调用,大家要在那么些中达成须求属性的初叶化*

if (minColumnHeight > columnH) {

[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {

/*

minColumnHeight = columnH;

//若是maxColumn列的最大y值小于obj,则让maxColumn等于obj所属的列

- prepareLayout

tempMinColumn = i;

if ([self.maxYDic[maxIndex] floatValue] < obj.floatValue) {

{

} else {}

maxIndex = key;

[super prepareLayout];

}

}

//初始化行距间距

tempMinColumn 便是相当的小的那一列

}];

self.minimumLineSpacing = LINESPACING;

x值就能够依照sectionInsets , 各个cell的左右区间,和cell的大幅算出 CGFloat cellX = self.sectionInsets.left tempMinColumn * (cellWeight self.interitemSpacing);

//collectionView的contentSize.height就等于最长列的最大y值 下内边距

self.minimumInteritemSpacing = INTERITEMSPACING;

y值:上边已经求出高度最小的那一列,以及最小的那一列的冲天。

return CGSizeMake(0, [self.maxYDic[maxIndex] floatValue]   self.sectionInset.bottom);

**

y值就 cellY = minColumnHeight

}

//早先化存款和储蓄容器

稳重://要是cell的y值不对等上个区的参天的冲天 即不是此区的第一列 要增多此区的各样cell的内外间距

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 方法

_attributes = [NSMutableDictionary dictionary];

if (cellY != self.lastContentHeight) {

该格局则用来设置每一个item的attributes,在此处,我们只须要简单的设置各种item的attributes.frame就能够

_colArray = [NSMutableArray arrayWithCapacity: COLUMNCOUNT];

cellY = self.lineSpacing;

首先我们必需识破collectionView的尺寸,然后大家依据collectionView的宽度,以及列数、各样间距来估测计算每一种item的宽窄

for (int i = 0; i < COLUMNCOUNT; i ) {

} else {}

item的大幅 = (collectionView的大幅 - 内边距及列边距) / 列数

[_colArray addObject: @];

那般就可以见道了 cell的frame了, 即attributes.frame = CGRectMake(cellX, cellY, cellWeight, cellHeight);

图片 14

}

2> 要更新 contentHeight (当前collectionView的原委的万丈) 和columnHeights(当区的每列的高度恐怕说每列的最后二个cell的y值 height)

CGFloat collectionViewWidth = self.collectionView.frame.size.width;

**

那么这么相应cell的值就计算甘休 ,在此函数重回值处增多到attrsArray 中去。

//self.sectionInset.left:左边距    self.sectionInset.right:右边距

//遍历全部item获取地点信息并开展仓储

第四部:同header的持筹握算方法一样 在- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath 计算footer的frame

//(self.columnCount - 1) * columnSpacing:一行中有着的列边距

NSUInteger sectionCount = [self.collectionView numberOfSections];

一同多少个区 ,各样区的header的frame是稍稍,每一个区中有稍许个cell 各类cell的frame是有一点点,每一种区的footer的frame是有个别,以此循环总计出富有的attributes,在- (NSArray *)layoutAttributesForElementsInRect:rect 再次回到总结的attributes

CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;

for (int section = 0; section < sectionCount; section ) {

注意 :在测算每一个attributes时 collectionView的开始和结果的万丈即contentHeight collectionView上个区的万丈的那一列的莫斯中国科学技术大学学即lastContentHeight 都在转移。

接下去总括item的坐标,要想计算坐标,那就必得了解最短的那一列,先遍历字典,找寻最短列是哪一列(minColumn)以及其最大y值。

NSUInteger itemCount = [self.collectionView numberOfSection: section];

在- collectionViewContentSize {

item的y值就也正是最短列的最大y值再拉长行间距,x值就格外右边距 (item宽度

for (int item = 0; item < itemCount; item ) {

return CGSizeMake(self.collectionView.frame.size.width, self.contentHeight);

  • 列间距) * minColumn

[self layoutItemFrameAtIndexPath: [NSIndexPath indexPathWithItem: item section: section]];

} 中回到collectionView ContentSize 完结布局。

图片 15

}

为了帮助扩张性和易用性,作者完全模拟 UICollectionViewFlowLayout 的用法设置代理方法和性质。至于其选用方法,和UICollectionViewFlowLayout 同样的。代理方法和性格如下。

//寻找最短的那一列

}

@property (nonatomic, weak) id delegate;

__block NSNumber *minIndex = @0;

}

// 区的sectionInsets

[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {

**

@property (nonatomic,assign) UIEdgeInsets sectionInsets;

if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) {

/**

//每一个区的列数

minIndex = key;

用来安装每贰个item的尺码,然后和indexPath存款和储蓄起来*

@property (nonatomic,assign) NSInteger columnCount;

}

/*

// 每个cell的左右间距

}];

- layoutItemFrameAtIndexPath: (NSIndexPath )indexPath*

@property (nonatomic,assign) CGFloat lineSpacing;

//根据最短列的列数总计item的x值

{

//每一个cell的左右距离

CGFloat itemX = self.sectionInset.left   (self.columnSpacing   itemWidth) * minIndex.integerValue;

CGSize itemSize = CGSizeMake(ITEMWIDTH, 100 arc4random1);

@property (nonatomic,assign) CGFloat interitemSpacing;

//item的y值 = 最短列的最大y值   行间距

//获取当前三列中度中中度最低的一列

//header的size

CGFloat itemY = [self.maxYDic[minIndex] floatValue]   self.rowSpacing;

NSUInteger smallestCol = 0;

@property (nonatomic,assign) CGSize headerReferenceSize;

接下去就是item的莫斯中国科学技术大学学,我们应有根据图片的原始尺寸以及总计出来的增长幅度,等比例缩放来总计高度,然则在layout类中,大家是拿不到图片的,因而大家得以定义三个block属性,恐怕代理,让外部来计量并赶回给我们,我们必要将item的宽度以及indexPath传递给外部:

CGFloat lessHeight = [_colArray[smallestCol] doubleValue];

// footer的size

@property (nonatomic, strong) CGFloat(^itemHeightBlock)(CGFloat itemHeight,NSIndexPath *indexPath);

for (int col = 1; col < _colArray.count; col ) {

@property (nonatomic,assign) CGSize footerReferenceSize;

依赖再次来到值来安装item的高度:

if (lessHeight < [_colArray[col] doubleValue]) {

上述的这么些参数 要是每种区都无差别,则足以在layout起首化的时候设置,如过各类区的参数设置都不等同,举例第叁个区是两列,第叁个区是一列,不用忧虑,用代理。

if (self.itemHeightBlock) itemHeight = self.itemHeightBlock(itemWidth, indexPath);

shortHeight = [_colArray[col] doubleValue];

代理方法帮助分区设置那个参数。

末段设置attributes的frame并更新字典:

smallestCol = col;

@protocol JWCCustomLayoutDelegate

//设置attributes的frame

}

@required

attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight);

}

// cell 高

//更新字典中的最短列的最大y值

//在眼下高度最低的列上边追加item而且存款和储蓄地点音信

- collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout heightForRowAtIndexPath:(NSIndexPath *)indexPath itemWidth:itemWidth ;

self.maxYDic[minIndex] = @(CGRectGetMaxY(attributes.frame));

UIEdgeInsets insets = self.collectionView.contentInset;

@optional

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 方法

CGFloat x = insets.left smallestCol (INTERITEMSPACING ITEMWIDTH);*

// headersize

该办法用来回到rect范围内,item的attributes

CGRect frame = {x, insets.top shortHeight, itemSize};

- collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;

直白重临attributesArray就能够

[_attributes setValue: indexPath forKey: NSStringFromCGRect];

// footer 的 size

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

[_colArray replaceObjectAtIndex: smallestCol withObject: @(CGRectGetMaxY];

- collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;

return self.attributesArray;

}

// 各样区的边距

}

**

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

使用

/**

// 各种区多少列

布局类写完了,接下去就足以一贯运用了

重返全数当前在可视范围内的item的布局属性*

- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout columnNumberAtSection:(NSInteger )section;

//创立布局对象

/*

// 各样区多少中央银行距

XRWaterfallLayout *waterfall = [[XRWaterfallLayout alloc] init];

- (NSArray )layoutAttributesForElementsInRect: rect*

- (NSInteger)collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout *)collectionViewLayout lineSpacingForSectionAtIndex:(NSInteger)section;

//设置相关属性

{

// 每种 item 之间的左右区间

waterfall.columnCount = 3;//共多少列

//获取当前具备可视item的indexPath。通过调用父类获取的布局属性数组会缺点和失误一部分可视item的布局属性

- collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout interitemSpacingForSectionAtIndex:(NSInteger)section;

waterfall.columnSpacing = 10;//列间距

NSMutableArray indexPaths = [NSMutableArray array];*

// 本区区头和上个区区尾的间隔

waterfall.rowSpacing = 10;//行间距

for (NSString rectStr in _attributes) {*

- collectionView:(UICollectionView *)collectionView layout:(JWCCustomLayout*)collectionViewLayout spacingWithLastSectionForSectionAtIndex:(NSInteger)section; (注意:在collectionViewFolwLayout中是力无法及设置当前的区头和上个区尾的间距的,为了弥补这一缺憾,特此加多那几个点子)

waterfall.sectionInset = UIEdgeInsetsMake(10, 10 , 10, 10);//内边距

CGRect cellRect = CGRectFromString;

如上只是大致计算步骤,具体落到实处代码见demo

[waterfall setItemHeightBlock:^CGFloat(CGFloat itemWidth, NSIndexPath *indexPath) {

if (CGRectIntersectsRect(cellRect, rect)) {

转发请评释出处 丹佛掘金队(Denver Nuggets)老 JI 谢谢

//依据图片的原始尺寸,及显示上涨的幅度,等比例缩放来总括显示中度

NSIndexPath indexPath = _attributes[rectStr];*

看完要是对您有用 请点赞鼓舞下中不中?藍 藍

XRImage *image = self.images[indexPath.item];

[indexPaths addObject: indexPath];

图片 16区头和区尾设置间距 ,第0区三列第一区四列 效果图图片 17单个区两列效果图

return image.imageH / image.imageW * itemWidth;

}

}];

}

collectionView.collectionViewLayout = waterfall;

**

//获取当前要来得的具备item的布局属性并再次回到

NSMutableArray layoutAttributes = [NSMutableArrayWithCapacity: indexPaths.count];*

[indexPaths enumerateObjectsUsingBlock: ^(NSIndexPath indexPath, NSUInteger idx, BOOL * stop) {*

UICollectionViewLayoutAttributes attributes = [self layoutAttributesForItemAtIndexPath: indexPath];*

[layoutAttributes addObject: attributes];

}];

return layoutAttributes;

}

**

/**

再次来到对应indexPath的布局属性*

/*

- (UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath: (NSIndexPath *)indexPath {*

UICollectionViewLayoutAttributes attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath: indexPath];*

for (NSString frame in _attributes) {*

if (_attributes[frame] == indexPath) {

attributes.frame = CGRectFromString;

break;

}

}

return attributes;

}

**

/**

设置collectionView的可滚动范围*

/*

- collectionViewContentSize

{

__block CGFloat maxHeight = [_colArray[0] floatValue];

[_colArray enumerateObjectsUsingBlock: ^(NSNumber height, NSUInteger idx, BOOL *stop) {*

if (height.floatValue > maxHeight) {

maxHeight = height.floatValue;

}

}

return CGSizeMake(CGRectGetWidth(self.collectionView.frame), maxHeight self.collectionView.contentInset.bottom);

}

**

/**

在collectionView的bounds发生更动的时候刷新布局*

/*

- shouldInvalidateLayoutForBoundsChange: newBounds

{

return !CGRectEqualToRect(self.collectionView.bounds, newBounds);

}

多说几句

使用collectionView实现职业须要之后,它差不离形成了自身最热衷的控件,相当高的可定制性决定了它的基本点地方。即便从代码完成的角度上的话,合适的布局几乎能够让大家兑现tableView,但它不是为着代替后面一个而出现的。collectionView相较tableView来讲,并不那么的大众化,毕竟常规的数目展现使用tableView就能够圆满彰显。

下边瀑布流的代码中,item的冲天是在layout里面随机生成的,但在事实上开辟中,高度的改换不应该由布局对象来成功。为了消除那一个标题,大家可以在自定义的布局对象中增添二个听从UICollectionViewDelegateFlowLayout的委托人属性:

@property (nonatomic, weak) id<UICollectionViewDelegateFlowLayout> delegate;

然后在prepareLayout方法中拉长一句self.delegate = self.collectionView.delegate。那样我们就足以经过向代理对象发送左券章程音信来博取itemSize(将item的尺寸交给controller来形成)。

除却上边提到的性质之外,UICollectionViewLayoutAttributes还应该有center、zIndex、transform3D等属质量让大家定制滑动的形变等卡通效果,比如卡牌动画就是本身特别心爱的效果与利益之一。另外还恐怕有上面多少个点子扶助大家在对item实行删除和足够操作的时候定制动画效果

initialLayoutAttributesForAppearingItemAtIndexPath:

initialLayoutAttributesForAppearingSupplementaryElementOfKind:atIndexPath:

initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:

finalLayoutAttributesForDisappearingItemAtIndexPath:

finalLayoutAttributesForDisappearingSupplementaryElementOfKind:atIndexPath:

finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:

关于那一个办法的选用能够学习那篇文章。

文集:iOS开发

转发注明原来的小说地址以及小编

本文由星彩网app下载发布于计算机编程,转载请注明出处:瀑布流的简便完成方式,自定义collocationViewLayo

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。