UICollectionView 关于自定义layout的一点见解
@interface CollectionWaterfallLayout : UICollectionViewLayout
/**
* 1、
* collectionView reload、invalidateLayout方法后会调用此方法
* 此方法中可能涉及大量布局运算
*/
- (void)prepareLayout
{
[super prepareLayout];
// code...
}
// newBounds 改变时给出条件是否需要将layout失效
// return YES to cause the collection view to requery the layout for geometry
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; information
// shouldInvalidateLayoutForBoundsChange 返回YES时调用,否则不调用
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds
可以在这里获取到UICollectionViewLayoutInvalidationContext,并主动调用以下方法完成具体的indexPath布局失效。
- (void)invalidateItemsAtIndexPaths:(NSArray *)indexPaths API_AVAILABLE(ios(8.0));
- (void)invalidateSupplementaryElementsOfKind:(NSString *)elementKind atIndexPaths:(NSArray *)indexPaths API_AVAILABLE(ios(8.0));
- (void)invalidateDecorationElementsOfKind:(NSString *)elementKind atIndexPaths:(NSArray *)indexPaths API_AVAILABLE(ios(8.0));
同时,collectionView会主动询问以下方法得到新的布局信息
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;
多次实验后得到的现象如下:
1.shouldInvalidateLayoutForBoundsChange->YES
2.invalidationContextForBoundsChange 不实现
3.prepareLayout 在每次滑动都会调用
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
/*
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds {
UICollectionViewLayoutInvalidationContext*context = [super invalidationContextForBoundsChange:newBounds];
return context;
}
*/
- (void)prepareLayout
{
[super prepareLayout];
// code...
}
实现了invalidationContextForBoundsChange,并在内部具体失效某个indexPath布局,那么prepareLayout并不会触发调用,会触发layoutAttributesForSupplementaryViewOfKind
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds {
UICollectionViewLayoutInvalidationContext*context = [super invalidationContextForBoundsChange:newBounds];
[context invalidateSupplementaryElementsOfKind:kSupplementaryViewKindHeader atIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];
return context;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
// 返回新的布局
}
通过此方法避免prepareLayout的频繁调用也是一种性能优化