iosanimationblockcakeyframeanimationcompletion-block

2 animations on same object, only last shows. How to show first one w/o nesting completion block?


I'm doing two animations on the same UIImageView, using blocks. Animations are not quite back to back, but almost; there is some logic inbetween.

If I implement this as above, only the second animation shows (this is normal behavior from what I understand). If I nest the logic and the second animation block inside the completion block of the first, I see both animations, but there's a fair amount of code to jam into that completion block and it just seems ugly and out of place.

In the non-nested configuration, why does iOS want to cut short the previous animations and execute only the final one, and how can I force it to wait on the first one before going to the next? I don't think it needs to block the main thread or "sit and spin" in a completion block; I just want all animations to be shown. Tried adding delay to second animation to no avail.

Is this a job for CAKeyframeAnimation?

// first animation

[UIView animateWithDuration:0.5
                      delay:0.0
                    options: UIViewAnimationCurveLinear
                 animations:^{movingColor.center = newCenter;
                     movingColor.transform = scaleTransform;}
                 completion:^(BOOL finished){ NSLog(@"forward animation done");}];

if (/* ...color is allowed at that location */) {

    // do some stuff

} else {

    // undo the animation

    [UIView animateWithDuration:0.5
                          delay:0.0
                        options: UIViewAnimationCurveLinear
                     animations:^{movingColor.center = origCenter;
                         movingColor.transform = scaleTransform;}
                     completion:^(BOOL finished){ NSLog(@"back animation done");}];
}

Solution

  • The second animation should be done conditionally inside the first's completion block. Putting it into a function will make it more readable.

    - (void)moveColor:(UIView *)view to:(CGPoint)center delay:(NSTimeInterval)delay completion:(void (^)(BOOL finished))complete {
    
        [UIView animateWithDuration:0.5 delay:delay options:UIViewAnimationCurveLinear animations:^{
            view.center = center;
            view.transform = scaleTransform;  // probably don't need this
        } completion:completion];
    }
    

    This way your logic can be separate from the animation code

    - (void)someMethod {
    
        [self moveColor:movingColor to:newCenter delay:0.0 completion:^(BOOL finished) {
            if (/*it can stay*/) {
                // stuff
            } else {
                [self moveColor:movingColor to:origCenter delay:2.0 completion:^(BOOL finished) {}];
            }
        }];
    }