Cancel a UIView animation?

Is it possible to cancel a UIView animation while it is in progress? Or would I have to drop to the CA level?

i.e. I’ve done something like this (maybe setting an end animation action too):

  • How to cancel UIViews block-based animation?
  • How to animate a UIView with constraints in Swift?
  • Auto Layout constraint change does not animate
  • Reimplement UIView block based animation methods with custom easing curve
  • How to animate UIImageViews like hatch doors opening
  • SubView slide in animation, iphone
  • [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:duration];
    [UIView setAnimationCurve: UIViewAnimationCurveLinear];
    // other animation properties
    
    // set view properties
    
    [UIView commitAnimations];
    

    But before the animation completes and I get the animation ended event, I want to cancel it (cut it short). Is this possible? Googling around finds a few people asking the same question with no answers – and one or two people speculating that it can’t be done.

    13 Solutions Collect From Internet About “Cancel a UIView animation?”

    The way I do it is to create a new animation to your end point. Set a very short duration and make sure you use the +setAnimationBeginsFromCurrentState: method to start from the current state. When you set it to YES, the current animation is cut short. Looks something like this:

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.1];
    [UIView setAnimationCurve: UIViewAnimationCurveLinear];
    // other animation properties
    
    // set view properties
    
    [UIView commitAnimations];
    

    Use:

    #import <QuartzCore/QuartzCore.h>
    
    .......
    
    [myView.layer removeAllAnimations];
    

    Simplest way to stop all animations on a particular view, immediately, is this:

    Link the project to QuartzCore.framework. At the start of your code:

    #import <QuartzCore/QuartzCore.h>
    

    Now, when you want to stop all animations on a view dead in their tracks, say this:

    [CATransaction begin];
    [theView.layer removeAllAnimations];
    [CATransaction commit];
    

    The middle line would work all by itself, but there’s a delay until the runloop finishes (the “redraw moment”). To prevent that delay, wrap the command in an explicit transaction block as shown. This works provided no other changes have been performed on this layer in the current runloop.

    On iOS 4 and greater, use the UIViewAnimationOptionBeginFromCurrentState option on the second animation to cut the first animation short.

    As an example, assume you have a view with an activity indicator. You wish to fade in the activity indicator while some potentially time consuming activity begins, and fade it out when the activity is finished. In the code below, the view with the activity indicator on it is called activityView.

    - (void)showActivityIndicator {
        activityView.alpha = 0.0;
        activityView.hidden = NO;
        [UIView animateWithDuration:0.5
                     animations:^(void) {
                         activityView.alpha = 1.0;
                     }];
    
    - (void)hideActivityIndicator {
        [UIView animateWithDuration:0.5
                     delay:0 options:UIViewAnimationOptionBeginFromCurrentState
                     animations:^(void) {
                         activityView.alpha = 0.0;
                     }
                     completion:^(BOOL completed) {
                         if (completed) {
                             activityView.hidden = YES;
                         }
                     }];
    }
    

    To cancel an animation you simply need to set the property that is currently being animated, outside of the UIView animation. That will stop the animation wherever it is, and the UIView will jump to the setting you just defined.

    If you are animating a constraint by changing the constant instead of a view property none of the other methods work on iOS 8.

    Example animation:

    self.constraint.constant = 0;
    [self.view updateConstraintsIfNeeded];
    [self.view layoutIfNeeded];
    [UIView animateWithDuration:1.0f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         self.constraint.constant = 1.0f;
                         [self.view layoutIfNeeded];
                     } completion:^(BOOL finished) {
    
                     }];
    

    Solution:

    You need to remove the animations from the layers of any views being affected by the constraint change and their sublayers.

    [self.constraintView.layer removeAllAnimations];
    for (CALayer *l in self.constraintView.layer.sublayers)
    {
        [l removeAllAnimations];
    }
    

    If you just want to pause/stop animation smoothly

    self.yourView.layer.speed = 0;
    

    Source: How to pause the animation of a layer tree

    None of the above solved it for me, but this helped: The UIView animation sets the property immediately, then animates it. It stops the animation when the presentation layer matches the model (the set property).

    I solved my issue, which was “I want to animate from where you look like you appear” (‘you’ meaning the view). If you want THAT, then:

    1. Add QuartzCore.
    2. CALayer * pLayer = theView.layer.presentationLayer;

    set the position to the presentation layer

    I use a few options including UIViewAnimationOptionOverrideInheritedDuration

    But because Apple’s documentation is vague, I don’t know if it really overrides the other animations when used, or just resets timers.

    [UIView animateWithDuration:blah... 
                        options: UIViewAnimationOptionBeginFromCurrentState ... 
                        animations: ^ {
                                       theView.center = CGPointMake( pLayer.position.x + YOUR_ANIMATION_OFFSET, pLayer.position.y + ANOTHER_ANIMATION_OFFSET);
                       //this only works for translating, but you get the idea if you wanna flip and scale it. 
                       } completion: ^(BOOL complete) {}];
    

    And that should be a decent solution for now.

    [UIView setAnimationsEnabled:NO];
    // your code here
    [UIView setAnimationsEnabled:YES];
    

    I have the same problem; the APIs don’t have anything to cancel some specific animation. The

    + (void)setAnimationsEnabled:(BOOL)enabled

    disables ALL animations, and thus does not work for me. There’s two solutions:

    1) make your animated object a subview. Then, when you want to cancel the animations for that view, remove the view or hide it. Very simple, but you need to recreate the subview without animations if you need to keep it in view.

    2) repeat the anim only one, and make a delegate selector to restart the anim if needed, like this:

    -(void) startAnimation {
    NSLog(@"startAnim alpha:%f", self.alpha);
    [self setAlpha:1.0];
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationRepeatCount:1];
    [UIView setAnimationRepeatAutoreverses:YES];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(pulseAnimationDidStop:finished:context:)];
    [self setAlpha:0.1];
    [UIView commitAnimations];
    }
    
    - (void)pulseAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    if(hasFocus) {
        [self startAnimation];
    } else {
        self.alpha = 1.0;
    }
    }
    
    -(void) setHasFocus:(BOOL)_hasFocus {
    hasFocus = _hasFocus;
    if(hasFocus) {
        [self startAnimation];
    }
    }
    

    Problem with 2) is that there’s always delay stopping the anim as it finishes the current animation cycle.

    Hope this helps.

    Even if you cancel the animation in the ways above animation didStopSelector still runs. So if you have logic states in your application driven by animations you will have problems. For this reason with the ways described above I use the context variable of UIView animations. If you pass the current state of your program by the context param to the animation, when the animation stops your didStopSelector function may decide if it should do something or just return based on the current state and the state value passed as context.

    CALayer * pLayer = self.layer.presentationLayer;
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView animateWithDuration:0.001 animations:^{
        self.frame = pLayer.frame;
    }];
    

    To pause an animation without reverting state to original or final:

    CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    myView.layer.speed = 0.0;
    myView.layer.timeOffset = paused_time;