Advanced UICollectionView animation using invalidateLayout calls

16,675

Solution 1

The answer to this is to use intermediate layouts.

[self.collectionView setCollectionViewLayout: layoutForStepOne animated:YES completion:^(BOOL finished) {
    [self.collectionView setCollectionViewLayout: layoutForStepTwo animated:YES completion:^(BOOL finished) {
        [self.collectionView setCollectionViewLayout: layoutForStepThree animated:YES];

    }];
}];

Solution 2

It is simple:

Create a new instance of some UICollectionViewLayout and use

- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated

to set the layout on your UICollectionView to this new layout object. Make sure you use YES for the animated parameter.

Edit: For doing multi staged animation i would try

performBatchUpdates:completion:

and put the next update into the completion block and repeat.

Share:
16,675
Michael Forrest
Author by

Michael Forrest

Creative Developer and Founder of Good To Hear. goodtohear.co.uk Music software obsessive. github.com/michaelforrest

Updated on June 22, 2022

Comments

  • Michael Forrest
    Michael Forrest about 2 years

    The UICollectionView Programming Guide says:

    In addition to animating insertions, deletions, and move operations, you can invalidate the layout at any time and force it to redraw its contents. Invalidating the layout does not animate items directly; when you invalidate the layout, the collection view displays the items in their newly calculated positions without animating. However, the act of invalidating the layout causes the layout object to move items explicitly. In a custom layout, you might use this behavior to position cells at regular intervals and create an animated effect.

    I've been trying something like this, where AnimationStep is an enum used by my UICollectionViewFlowLayout subclass to conditionally set the positions of tiles with a three stage animation:

    -(void)update{
        [self animateLayoutAfterDelay:2.0 toStep:AnimationStepOne];
        [self animateLayoutAfterDelay:4.0 toStep:AnimationStepTwo];
        [self animateLayoutAfterDelay:6.0 toStep:AnimationStepThree];
    }
    
    -(void)animateLayoutAfterDelay:(NSTimeInterval)delay toStep:(MagazineLayoutAnimationStep)step {
        double delayInSeconds = delay;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [UIView animateWithDuration:2.0 animations:^{
                self.layout.animationStep = step;
                [self.layout invalidateLayout];
            }];
        });
    }
    

    This has quite unpredictable effects. Some cells animate in the way I'd expect, some get hidden and shown or just appear in their new locations. I put random background colours on the cells to see if this might be the effect of UICollectionView recycling cells and sure enough, sometimes it was. Which explains some of the weirdness, but not all of it.

    Does anybody know how Apple want me to animate cells and move them around?

    (I need this because my collection view cells tend to change size and I want a graceful animation without any diagonal movement).

  • Michael Forrest
    Michael Forrest about 11 years
    I've since changed how I'm doing this but I would like to be able to accept this answer if it does solve my original problem. Surely replacing the whole layout would make it even more difficult to do a multi-stage animation in which the original positions were referenced in order to transition to the new positions?