UICollectionViewLayoutInvalidationContext的一点理解

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的频繁调用也是一种性能优化

你可能感兴趣的:(UICollectionViewLayoutInvalidationContext的一点理解)