Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView performBatchUpdates: animates all sections

I'm writing a custom UICollectionViewFlowLayout and I've noticed that initialLayoutAttributesForAppearingItemAtIndexPath: and initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath: will be called for all sections when I invoke performBatchUpdates:completion: on the collection view. The result is that all sections have the animation applied to them instead of just the newly added section.

[collectionView performBatchUpdates:^{
    currentModelArrayIndex++;
    [collectionView insertSections:[NSIndexSet indexSetWithIndex:currentModelArrayIndex]];
    [collectionView reloadSections:[NSIndexSet indexSetWithIndex:currentModelArrayIndex-1]];
} completion:^(BOOL finished) {
    [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:currentModelArrayIndex] atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
}];

What I've tried so far is removing the call to performBatchUpdates:completion: in lieu of simple updates, but the already existing sections (all of them) are animated in anyway. I've come up with a solution of checking to make sure that I'm changing the layout attributes of only the last section, but it feels hacky.

if (decorationIndexPath.section == [(id<UICollectionViewDataSource>)self.collectionView.delegate numberOfSectionsInCollectionView:self.collectionView] - 1)
{
   layoutAttributes.alpha = 0.0f;
   layoutAttributes.transform3D = CATransform3DMakeTranslation(-CGRectGetWidth(layoutAttributes.frame), 0, 0);
}

Is this the proper way to go about animating only some sections?

like image 981
Ash Furrow Avatar asked Jan 13 '13 19:01

Ash Furrow


1 Answers

OK, I've got an answer; it's not a lot prettier than the previous one, but it keeps the layout from touching the datasource, so it's cleaner.

Basically, we need to override prepareForCollectionViewUpdates: and finalizeCollectionViewUpdates to keep track of the sections that we're inserting. I have a mutable set that contains NSNumber instances of the sections that we're inserting.

-(void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
    [super prepareForCollectionViewUpdates:updateItems];

    [updateItems enumerateObjectsUsingBlock:^(UICollectionViewUpdateItem *updateItem, NSUInteger idx, BOOL *stop) {
        if (updateItem.updateAction == UICollectionUpdateActionInsert)
        {
            [insertedSectionSet addObject:@(updateItem.indexPathAfterUpdate.section)];
        }
    }];
}

-(void)finalizeCollectionViewUpdates
{
    [super finalizeCollectionViewUpdates];

    [insertedSectionSet removeAllObjects];
}

Next, I check to see if the index path's section is included in that set when setting the initial layout attributes for items and decoration views.

-(UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes;

    if ([elementKind isEqualToString:AFCollectionViewFlowLayoutBackgroundDecoration])
    {
        if ([insertedSectionSet containsObject:@(decorationIndexPath.section)])
        {
            layoutAttributes = [self layoutAttributesForDecorationViewOfKind:elementKind atIndexPath:decorationIndexPath];
            layoutAttributes.alpha = 0.0f;
            layoutAttributes.transform3D = CATransform3DMakeTranslation(-CGRectGetWidth(layoutAttributes.frame), 0, 0);
        }
    }

    return layoutAttributes;
}

-(UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes;

    if ([insertedSectionSet containsObject:@(itemIndexPath.section)])
    {
        layoutAttributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
        layoutAttributes.transform3D = CATransform3DMakeTranslation([self collectionViewContentSize].width, 0, 0);
    }

    return layoutAttributes;
}

I'm returning nil from these methods otherwise because nil is the default value.

This has the added benefit of having nicer rotation animations, as well.

like image 61
Ash Furrow Avatar answered Oct 16 '22 04:10

Ash Furrow