How to cancel UIView block-based animation?
Asked Answered
B

4

94

I've searched loads of SO stuff and in Apple's references, but still unable to manage my problem.

What I have:

  1. A screen with 2 UIImageViews and 2 UIButtons connected to them
  2. 2 kinds of animation:
    1. Scaling up and then down of each image, one after another, only once in viewDidLoad
    2. When a button pressed (a custom button hidden 'inside' of each UIImageView) it triggers animation of appropriate UIImageView–only one, not both–(also scale up, then down).
    3. As I am writing for iOS4+ I'm told to use block based animations!

What I need:

How do I cancel a running animation? I've managed to cancel after all but the last one... :/

Here is my code snippet:

[UIImageView animateWithDuration:2.0 
                               delay:0.1 
                             options:UIViewAnimationOptionAllowUserInteraction 
                          animations:^{
        isAnimating = YES;
        self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
    } completion:^(BOOL finished){
        if(! finished) return;
        [UIImageView animateWithDuration:2.0 
                                   delay:0.0 
                                 options:UIViewAnimationOptionAllowUserInteraction 
                              animations:^{
            self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
        } completion:^(BOOL finished){
            if(! finished) return;
            [UIImageView animateWithDuration:2.0 
                                       delay:0.0 
                                     options:UIViewAnimationOptionAllowUserInteraction 
                                  animations:^{
                self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
            } completion:^(BOOL finished){
                if(! finished) return;
                [UIImageView animateWithDuration:2.0 
                                           delay:0.0 
                                         options:UIViewAnimationOptionAllowUserInteraction 
                                      animations:^{
                    self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
                }
                                      completion:^(BOOL finished){
                                          if (!finished) return;
                                          //block letter buttons
                                          [self.bigLetterButton setUserInteractionEnabled:YES];
                                          [self.smallLetterButton setUserInteractionEnabled:YES];
                                          //NSLog(@"vieDidLoad animations finished");
                                      }];
            }];
        }];
    }];

Somehow the smallLetter UIImageView is not working properly, because when pressed (through button) bigLetter is canceling animations properly...

EDIT: I've used this solution, but still having problem with scaling down smallLetter UIImageView - not cancelling at all... solution

EDIT2: I've added this at the beginning of next/prev methods:

- (void)stopAnimation:(UIImageView*)source {
    [UIView animateWithDuration:0.01
                          delay:0.0 
                        options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
                     animations:^ {
                         source.transform = CGAffineTransformIdentity;
                     }
                     completion:NULL
     ];
}

problem stays... :/ no idea how to interrupt last animation for letters in animation chain

Botch answered 5/3, 2012 at 16:9 Comment(2)
Hey I think Hari Kunwar's answer should be accepted now.Photolithography
These days you must use UIViewPropertyAnimator - it's tremendously easier, also.Vitelline
I
161

You can stop all animations on a view by calling:

[view.layer removeAllAnimations];

(You'll need to import the QuartzCore framework to call methods on view.layer).

If you want to stop a specific animation, not all animations, your best best bet is to use CAAnimations explicitly rather than the UIView animation helper methods, then you will have more granular control and can stop animations explicitly by name.

The Apple Core Animation documentation can be found here:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html

Ischia answered 12/3, 2012 at 23:57 Comment(3)
Just want to add, in my own observation, subsequent animateWithDuration doesn't work anymore after calling removeAllAnimations. This is for doing pagination and pull to refresh controls, perhaps someone else might observe something different. I end up using CABasicAnimation and calling [myView.layer removeAnimationForKey:@"animationKey"];Caruso
Thanks for the tip @Nick - just a heads up that the link no longer seems to be supported, try this one instead: developer.apple.com/library/ios/documentation/Cocoa/Conceptual/…Egwan
after view.layer.removeAllAnimations() add animate view again not workingSpiritualist
C
72

For iOS 10 use UIViewPropertyAnimator to animate. It provides methods to start, stop and pause UIView animations.

 let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
        self.view.alpha = 0.0
 }
 // Call this to start animation.
 animator.startAnimation()

 // Call this to stop animation.
 animator.stopAnimation(true)
Connivent answered 30/12, 2016 at 20:20 Comment(1)
Adding a comment to catch your eye, extremely relevant answer for newer codePul
F
4

I'd add to Nick's answer that to make removeAllAnimations smooth next idea be very handy.

[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
                  duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
                      [view.layer displayIfNeeded];
                  } completion:nil];
Fehr answered 19/10, 2014 at 23:35 Comment(0)
S
0

You can try this (in Swift):

UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)

Note: you can put code between those two calls if necessary, for example:

UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)
Splint answered 18/2, 2019 at 21:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.