UICollectionView之自定义Layout
当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以考虑自定义layout。
所以,了解并学习一下自定义Layout是很有必要。
其实可以分三个步骤:
- 覆写prepareLayout方法,并在里面事先就计算好必要的布局信息并存储起来。
- 基于prepareLayout方法中的布局信息,使用collectionViewContentSize方法返回UICollectionView的内容尺寸。
- 使用layoutAttributesForElementsInRect:方法返回指定区域cell、Supplementary View和Decoration View的布局属性。
了解了自定义布局的三个主要步骤,我们来通过自定义布局的方式用UICollectionView实现grideView。当然,grideView使用UICollectionViewFlowLayout
就可以轻易实现,这里我们只是学习了解一下自定义布局的过程,所以拿grideView这个经常用的来作为例子。
我们创建一个新的工程BGCustomLayoutCollectionViewDemo。然后创建一个UICollectionViewLayout的子类对象BGGrideLayout
,它就是我们自定义layout对象。
在BGGrideLayout里面,我们首先覆写prepareLayout方法。
prepareLayout是专门用来准备布局的,在prepareLayout
方法里面我们可以事先就计算后面要用到的布局信息并存储起来,防止后面方法多次计算,提高性能。例如,我们可以在此方法就计算好每个cell的属性、整个CollectionView的内容尺寸等等。此方法在布局之前会调用一次,之后只有在调用invalidateLayout
、shouldInvalidateLayoutForBoundsChange:
返回YES
和UICollectionView刷新
的时候才会调用。
而在BGGrideLayout的prepareLayout方法中,我们有两个目的:
一是获取对应indexPath的UICollectionViewLayoutAttributes
对象,并存储到二维数组layoutInfoArr
当中;
二是计算出内容尺寸并保存到全局变量contentSize
当中。
代码如下:
|
|
在上面的代码中,我们看到了UICollectionViewLayoutAttributes
这个类,这个类其实专门用来存储视图的内容,例如frame、size、apha、hiden等等,layout最后会拿着这些frame设置给对应的视图。
而上面代码中,获取UICollectionViewLayoutAttributes
是通过layoutAttributesForItemAtIndexPath:
方法
|
|
在这个方法中,itemSize
是cell的大小,interitemSpacing
是cell与cell之间的间距,lineSpacing
是行距。
随后,覆写collectionViewContentSize
collectionViewContentSize返回内容尺寸给UICollectionView。注意这个方法返回的尺寸是给UICollectionView这个继承于UIScrollView
的视图作为contentSize
,不是UICollectionView的视图尺寸。正是因为这一点,我们自定义layout如果想让它只能横向滑动,只需要将这个size.height
设置成collectionView.height
就行了。
这个方法会多次调用,所以最好是在prepareLayout里就计算好。
在BGGrideLayout类中,我们只需要返回前面计算好的内容尺寸就行了。
|
|
最后,覆写layoutAttributesForElementsInRect:方法
此方法需要返回一组UICollectionViewLayoutAttributes类型对象。它代表着在这个指定的区域中,我们需要显示cell
、Supplementary View
和Decoration View
中哪些视图,而这些视图的属性则保存UICollectionViewLayoutAttributes中。
此方法会多次调用,为了更好的性能,在这个方法当中,我们使用的UICollectionViewLayoutAttributes最好是在prepareLayout已经布局好的信息。
在BGGrideLayout中,我们遍历二维数组,找出了与指定区域有交接的UICollectionViewLayoutAttributes对象放到一个数组中,然后返回。
|
|
到这里,我们的BGGrideLayout已经写好了,使用部分的代码,请直接查看BGCustomLayoutCollectionViewDemo中ViewController里面的代码就行了。
效果: