nonopolarity
nonopolarity

Reputation: 151166

In iOS, what happens when a view animation is started while it is already animating?

When a view is animated by a gesture recognizer of tapping the main view:

-(void) doAnimate {
    [UIView animateWithDuration:3 

                     animations:^{
                         self.circleView.center = CGPointMake(100, 300);
                     }

                     completion:^(BOOL finished) {
                         NSLog(@"finished is %i", finished);
                         [UIView animateWithDuration:1 animations:^{
                             self.circleView.center = CGPointMake(250, 300);
                         }];
                     }
     ]; 
}

(there is chained animation). If it is animating and the main view is tapped again, I actually see the completion handler called twice, first with TRUE, and the second time with FALSE. I thought it was to be called only once, with FALSE? I can't find it in Apple's doc. Is there a rule for how it works if animation starts when it is already animating? (I think it apply it is the same view being animated again, and doesn't apply if view2 is animated while view1 is animating?)


Update: the following code can show more insight:

-(void) dropAnimate:(UIGestureRecognizer *) g {

    int n = arc4random() % 10000;
    int y = 501 + arc4random() % 200;
    NSLog(@"y is %i", y);
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, y, 10, 10)];
    label.text = @"x";
    [self.view addSubview:label];

    [UIView animateWithDuration:3 

                     animations:^{
                         NSLog(@"n is %i", n);
                         self.circleView.center = CGPointMake(100, y);
                     }
                     completion:^(BOOL finished) {
                         NSLog(@"n is %i", n);
                         NSLog(@"finished is %i   y is %i", finished, y);
                         [UIView animateWithDuration:3 animations:^{
                             self.circleView.center = CGPointMake(250, y);
                         }
                          ];

                     }

     ];
    NSLog(@"finished the method call");

}

In addition to @Kai's answer below, it seems that there is a rule to new animation for the same UIView object when there is already an animation going on: the old animation will finish its effect immediately, and the new animation is run, but then next the old animation's completion is called with NO, and now a 3rd animation is started, which causes animation 2 to finish the effect, but next its completion block is called, with a NO, and it causes animation 3 to take effect immediately... and we see animation 4 running for 3 seconds.

The above sample code can be tried... and to simplify it, just remove the completion block, and then try it, and it confirms to the rule that says: if we start a new animation on the same object, the old animation takes effect immediately, and the new animation is run...

And with the completion block, it can get quite complicated if the completion block starts yet another animation...

So I think a finally thing is: does any docs or spec specify this behavior?

Upvotes: 4

Views: 1563

Answers (1)

Kai Huppmann
Kai Huppmann

Reputation: 10775

I think what happens is the following:

Your first trigger sets the center to (100,300) and than animates the view (note that the center property changes before you actually see it!). Your second trigger returns immediately (calls completion with YES), because there is nothing to animate (the property's already been set to the very same value before) and resets the center and by that forces the first animation (still running) to stop with NO, because the circleview is teared out from it's disired animation by getting a new center (note that the 2nd trigger does not disturb the 1st animation before calling completion, because the circleview's center property is not changed).

Upvotes: 1

Related Questions