andrewmobile
andrewmobile

Reputation: 188

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");}];
}

Upvotes: 0

Views: 1568

Answers (3)

danh
danh

Reputation: 62676

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) {}];
        }
    }];
}

Upvotes: 1

Svein Halvor Halvorsen
Svein Halvor Halvorsen

Reputation: 2494

The animateWithDuration is executed asynchronously, and returns right away. That is, the next line of code is executed without waiting for the animation to finish. You either put your code in the completion block if you want it to be executed after the animation is finished, or you accept that the second animation is started (thus canceling the first) immediately.

If you want to indicate to the user that something was wrong by starting the animation, but not completing it, you could execute the second animation with a delay. Remember to also set the the UIViewAnimationOptionBeginFromCurrentState option if you delay the second animation with less than the duration of the first:

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

Upvotes: 1

Omar Abdelhafith
Omar Abdelhafith

Reputation: 21221

The correct way to do it is as you said to set the second one in the completition of the first one that is the correct way,

You can also adda delay on the start of the other, this may or may not work it depends on alot of variables

Your second animation will have a delay of .5 (time for first animation to complete )

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

Upvotes: 1

Related Questions