如果有以下需求才使用自定义布局:
2.频繁需要更改cell的位置,更改流布局还不如自定义一个时。
自定义布局的难点在于计算布局中每个item的位置,如果有了位置,就很简单了。
继承UICollectionViewLayout
需要实现的核心任务:
1.指定滚动区域的尺寸
2.为布局中的每一个cell或view指定attribute对象,从而使collection view得到item的位置。
在布局过程中,使用collectionView属性从数据源获取数据。
理解核心布局过程
集合视图和布局对象协同工作,只要集合视图需要布局信息,就向布局对象询问。集合视图第一次出现,或者尺寸改变都会获取布局信息,可以显式调用invalidateLayout方法强制重新布局。
invalidateLayout与reloadData区别很大,重新布局不会刷新数据。在数据源中的数据变化时,reloadData才是合适的。
在布局过程中,集合视图调用了布局对象中的几个特定方法:
1.在prepareLayout方法中完成布局信息的预处理。
2.在collectionViewContentSize中基于预处理完成全部计算。
3.在layoutAttributesForElementsInRect:中返回设定好的attribute。
invalidateLayout方法并不会马上开始布局更新,仅仅标记了布局需要更新,在下一次视图更新循环中,集合视图发现布局需要更新时,才会更新布局。
生成布局属性
1.layoutAttributesForCellWithIndexPath:
2.layoutAttributesForSupplementaryViewOfKind:withIndexPath:
3.layoutAttributesForDecorationViewOfKind:withIndexPath:
至少为布局属性设置尺寸和位置,zIndex用于防止重叠,isEqual:方法需要重写,集合视图调用用于某些计算。
准备布局
在这完成准备工作。
为指定区域中的item设置attribute
layoutAttributesForElementsInRect:方法的步骤:
1.遍历prepareLayout方法中准备的数据,填入缓存的attribute,没有就生成一个;
2.检查每个item的尺寸,看看在不在要布局的矩形区域内;
3.对于在区域内的item,添加一个对应的attribute对象到数组中
4.返回attribute对象数组
需要立刻返回布局属性的情况
layoutAttributesForItemAtIndexPath:
layoutAttributesForSupplementaryViewOfKind:atIndexPath:
layoutAttributesForDecorationViewOfKind:atIndexPath:
这些方法的实现需要取到指定item的当前布局属性并返回。每个自定义布局对象都重写实现第一个方法,如果没有supplementary view可以不重写第二个方法,如果没有decoration view可以不重写第三个方法,在这几个方法中不能更新布局属性。
让自定义布局更加迷人
有一些方法推荐实现,效果更好。
使用附属视图为内容增色
附属视图与cell是分离开的,有另一套布局属性。附属视图的数据来自数据源,用于说明主内容。流布局使用附属视图作为区头区尾,有的应用使用附属视图为每一个cell提供了一个说明文本。附属视图应该是UICollectionReusableView的子类。
为布局添加附属视图的步骤:
1.在集合视图中注册附属视图,registerClass:forSupplementaryViewOfKind:withReusableIdentifier:或者
registerNib:forSupplementaryViewOfKind:withReuseIdentifier:
2.在数据源中实现collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法,使用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:重用或新建附属视图,设置后返回
3.像为cell设置布局属性一样为附属视图设置布局属性
4.在layoutAttributesForElementsInRect:方法的返回数组中加入附属视图的布局属性
5.实现layoutAttributesForSupplementaryViewOfKind:atIndexPath:方法,在需要时返回特定附属的布局属性
附属视图的布局过程与cell一样,但是附属视图可以有多种附属视图样式。因为不同的cell内容可能需要有不同的附属视图来配合,附属视图有一个额外的kind字段描述。
在自定义布局中加入装饰视图
装饰视图是用于改善集合视图外观的视图,只有外观所以不需要数据源。可以使用装饰视图实现cell的个性化。
添加装饰视图的步骤:
1.使用registerClass:forDecorationViewOfKind:或者registerNib:forDecorationViewOfKind:注册装饰视图。
2.在布局对象的layoutAttributesForDecorationViewOfKind:atIndexPath:方法中为装饰视图设置布局属性。
3.实现layoutAttributesForDecorationViewOfKind:atIndexPath:,并在需要时返回布局属性。
4.可选实现,initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:和finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:用于处理装饰视图的动态出现、消失效果。
所有的配置都在initWithFrame:中完成,必须是UICollectionReusableView的子类。为装饰视图设置布局属性时,需要考虑zIndex,防止遮盖。
实现自定义布局的技巧
1.在prepareLayout方法中创建、保存稍后要用的UICollectionViewLayoutAttributes。在item少的时候缓存有效,多的时候就得考虑了。
2.不要继承UICollectionView。
3.绝不要在layoutAttributesForElementsInRect:方法中使用UICollectionView的visibleCells属性,会产生循环。有时候,布局对象需要通过数据源定位item。