ios - stop - uiviewpropertyanimator




Cancel a UIView animation? (10)

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):

[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.


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.


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.



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.


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.


Sorry to resurrect this answer, but in iOS 10 things kinda changed, and now cancelling is possible and you can even cancel gracefully!

After iOS 10 you can cancel animations with UIViewPropertyAnimator!

UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: {
    view.backgroundColor = .blue
})
animator.stopAnimation(true)

If you pass true it cancels the animation and it stops right where you cancelled it. The completion method will not be called. However, if you pass false you are responsible for finishing the animation:

animator.finishAnimation(.start)

You can finish your animation and stay in the current state (.current) or go to the initial state (.start) or to the end state (.end)

By the way, you can even pause and restart later...

animator.pauseAnimation()
animator.startAnimation()

Note: If you don't want an abrupt cancelling you can reverse your animation or even change your animation after you pause it!


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];

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.


Use:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];

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




uiviewanimation