Benedict Cohen
Benedict Cohen

Reputation:

How do I trigger a callback when a NSAnimationContext ends?

I have an animation which moves some views around. When this animation completes I want the window to recalculate the keyview loop. My code is simmilar to the follow mock code:

[NSAnimationContext beginGrouping];        
[newView setAlpha: 0.0]; //hide newView
[self addSubView:newView];

//position the views
[[oldView animator] setFrame: newFrame1];
[[newView animator] setFrame: newFrame2];

[[newView animator] setAlpha: 1.0]; //fade-in newView

[NSAnimationContext endGrouping]; 

[[self window] recalculateKeyViewLoop];

The problem with this code is that recalculateKeyViewLoop is called before the views are in their new positions which means that the keyviewloop is wrong.

How do I fix this?

My first though is to call recalculateKeyViewLoop in a callback from when the animation ends but I can't figure out how to do this.

Upvotes: 4

Views: 3595

Answers (6)

Jay Haase
Jay Haase

Reputation: 1989

You can use a completion handler like this:

[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
    // Start some animations.
    [[myView animator] setFrameSize:newViewSize];
    [[myWindow animator] setFrame:newWindowFrame display:YES];
} completionHandler:^{
    // This block will be invoked when all of the animations started above have completed or been cancelled.
    NSLog(@"All done!");
}];

Upvotes: 1

lmirosevic
lmirosevic

Reputation: 16317

If you are animating an NSWindow (as opposed to an NSView), the other answers will not work and you should do this instead:

CAAnimation *animation = [CABasicAnimation animation];
animation.delegate = self;
self.window.animations = @{@"frame": animation};
[[self.window animator] setFrame:NSMakeRect(0, 0, 400, 200) display:YES];

which will then call the animationDidStop:finished: method on your delegate (which in the above code would be self)

Upvotes: 0

Tyler
Tyler

Reputation: 1603

Check out my post here: How would I do this iOS animation on OSX?

I wrote a class that handles this for you, using blocks. Hopefully your target allows blocks! :)

Upvotes: 0

Ashley Clark
Ashley Clark

Reputation: 8823

Something that's not so obvious, or at least wasn't to me, is that there are two animations going on when you do a setFrame:, with keys frameSize and frameOrigin.

Depending on what your original and final frames are you may need to register yourself as a delegate for one or both of them.

I'd also recommend that you make a copy of the animation you get back from -animationForKey: and store your modified copy in the animations dictionary of your object. This way your delegate will only be called at the conclusion of that particular objects' animator duration, versus all objects animating that key.

eg.

CAAnimation *animation = [[view animationForKey:@"frameOrigin"] copy];
animation.delegate = self;
[view setAnimations:[NSDictionary dictionaryWithObject:animation forKey:@"frameOrigin"]];

In this way your animation object will supersede the default animation object for that view. Then implement whichever delegate methods you're interested in.

Upvotes: 5

Peter Hosey
Peter Hosey

Reputation: 96333

You should be able to send -animationForKey: to your views to get a CAAnimation instance, then set yourself as its delegate and implement the method that Adam mentioned.

Upvotes: 4

adam
adam

Reputation: 22587

if you use CAAnimation this has an animationDidStop:finished: delegate method..

http://developer.apple.com/documentation/GraphicsImaging/Reference/CAAnimation_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAAnimation

Hope this helps

Upvotes: 1

Related Questions