其代理方法和属性模仿UICollectionViewFlowLayout 所写,使用方法和UICollectionViewFlowLayout类似
功能描述:
1 > 满足UICollectionViewFlowLayout提供的普通的线性布局和网格布局
2 > 满足单区和多区的瀑布流布局。
3 > 满足多区瀑布流时每个区的列数可以不同
4 > 满足设置header和footer
5 > 满足设置header和footer的间距
注意:本文不涉及到装饰视图的相关代理方法以及计算。
首先要明白的事情:collectionView与collocationViewLayout的关系。
collocationView负责展示,collectionviewLayout负责提供如何展示,包括cell的大小位置,header和footer的大小位置等,UICollectionViewFlowLayout 继承自UICollectionViewLayout是苹果公司封装好的layout,可以实现简单的网格和线性布局,当cell的大小和间距一样时可以用UICollectionViewFlowLayout,如果要实现比较复杂的布局,就需要自定义了。
其次,要了解UICollectionViewLayoutAttributes 类的属性,以下是每一个cell的属性,都是通过UICollectionViewLayoutAttributes属性体现出来的。
1 2 3 4 5 6 7 8 9 | |
还有,要理解UICollectionViewLayout的几个方法:
1. prepareLayout :是专门用来准备布局的,在prepareLayout方法里面我们可以事先就计算后面要用到的布局信息并存储起来,防止后面方法多次计算,提高性能。例如,我们可以在此方法就计算好每个cell的属性、整个CollectionView的内容尺寸等等。此方法在布局之前会调用一次,之后只有在调用invalidateLayout、shouldInvalidateLayoutForBoundsChange:返回YES和UICollectionView刷新的时候才会调用。
2.
1 | |
返回对应的indexPath的cell的attributes
3.
1 | |
返回对应的header和footer的attributes
4.
1 | |
;collectionView的size 这个size不是可视范围的size是整个collectionView的size
5.
1 | |
返回在rect范围内所有cell footer和head的attribute
了解以上的几点就可以开始计算了。计算的顺序是从上到下,即从区头到每个区的cell再到区尾
设置一些数组用于存储计算好的值:如下
1 2 3 4 5 6 7 8 9 10 | |
首先是重写 prepareLayout方法,也是最重要的一步。在此方法中完成初始化。所有的计算都置为零。
第一步:通过
1 | |
方法获取collectionView中一共有几个区。设置一个for循环。
第二步:通过
1 | |
获取每个header的属性。计算完成之后把attributes添加到attrsArray 数组中 ,同时还有根据sectionInsets 等参数改变contentHeight 的高度
第三步: 设置区头完成之后,在循环中根据
1 | |
获取相应的区有多少个cell
在这一步中计算是最麻烦的。可以分为如下步骤:
1> 计算每一个cell的frame。 根据此区中一共有几列和屏幕的宽度,以及每个cell的之间的间距,计算出每个cell的宽度,因为高度是外面传过来的,所以高度不需要计算 。那么还需要知道cell的x值和y值。
x值:首先取出当前区的中哪一列最低。
1 2 3 4 5 6 7 8 9 | |
tempMinColumn 就是最小的那一列
x值就可以根据sectionInsets , 每个cell的左右间距,和cell的宽度算出
1 | |
y值:上面已经求出高度最小的那一列,以及最小的那一列的高度。
y值就 cellY = minColumnHeight
注意://如果cell的y值不等于上个区的最高的高度 即不是此区的第一列 要加上此区的每个cell的上下间距
1 2 3 | |
这样就可以知道了 cell的frame了, 即attributes.frame = CGRectMake(cellX, cellY, cellWeight, cellHeight);
2> 要更新 contentHeight (当前collectionView的内容的高度) 和columnHeights(当区的每列的高度或者说每列的最后一个cell的y值 + height)
那么这样相应cell的值就计算完毕 ,在此函数返回值处添加到attrsArray 中去。
第四部:同header的计算方式一样 在
1 | |
计算footer的frame
一共多少个区 ,每个区的header的frame是多少,每个区中有多少个cell 每个cell的frame是多少 ,每个区的footer的frame是多少,以此循环计算出所有的attributes,在- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 返回计算的attributes
- 注意 :在计算每个attributes时 collectionView的内容的高度即contentHeight collectionView上个区的最高的那一列的高度即lastContentHeight 都在改变。
在
1 2 3 | |
中返回collectionView ContentSize 完成布局。
为了支持扩展性和易用性,我完全模仿 UICollectionViewFlowLayout 的用法设置代理方法和属性。至于其使用方法,和UICollectionViewFlowLayout 一样的。代理方法和属性如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
上述的这些参数 如果每个区都一样,则可以在layout初始化的时候设置,如过每个区的参数设置都不一样,比如第一个区是两列,第二个区是一列,不用担心,用代理。
代理方法支持分区设置这些参数。
@protocol JWCCustomLayoutDelegate
@required
// cell 高
1 | |
@optional
// headersize
1 | |
// footer 的 size
1 | |
// 每个区的边距
1 | |
// 每个区多少列
1 | |
// 每个区多少中行距
1 | |
// 每个 item 之间的左右间距
1 | |
// 本区区头和上个区区尾的间距
1 | |