Reputation: 966
// wc here is an NSWindowController
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5f];
if (duplication) {
NSPoint origin = initialSize.origin;
origin.y += initialSize.size.height;
origin = [wc.window cascadeTopLeftFromPoint:origin];
origin.y -= initialSize.size.height;
//[[wc.window animator] setFrameOrigin:origin]; // Why setFrameOrigin and cascadeTopLeftFromPoint are not animated?
initialSize.origin = origin;
[[wc.window animator] setFrame:initialSize display:YES];
}
// This block should be invoked when all of the animations started above have completed or been cancelled.
// For not to show the edit window till the duplication animation not finished
[NSAnimationContext currentContext].completionHandler = ^{
if (edit)
[wc editDocument:self];
else
if (fullScreen)
[wc.window toggleFullScreen:self];
};
[NSAnimationContext endGrouping];
In this case the completion block executed but unfortunately does not wait for the window reposition be finished, instead it opens the window's edit sheet immediately and moves them together.
The most strange thing is that a few lines above in the same source file the same type of completition block works fine :-O
What am I missing here?
Upvotes: 3
Views: 2118
Reputation: 132919
Check the documentation of completionHandler
:
If set to a non-nil value, a context’s completionHandler is guaranteed to be called on the main thread as soon as all animations subsequently added to the current NSAnimationContext grouping have completed or been cancelled.
The completion handler only affects animations added after the completion handler has been set.
At the end it also says:
If no animations are added before the current grouping is ended—or the completionHandler is set to a different value—the handler will be invoked immediately.
In your case, no animations are added between setting a completion handler and the end of the current grouping, thus your completion handler is called immediately.
The correct code would be:
// wc here is an NSWindowController
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5f];
// This block should be invoked when all of the animations started above have completed or been cancelled.
// For not to show the edit window till the duplication animation not finished
[NSAnimationContext currentContext].completionHandler = ^{
if (edit)
[wc editDocument:self];
else
if (fullScreen)
[wc.window toggleFullScreen:self];
};
if (duplication) {
NSPoint origin = initialSize.origin;
origin.y += initialSize.size.height;
origin = [wc.window cascadeTopLeftFromPoint:origin];
origin.y -= initialSize.size.height;
//[[wc.window animator] setFrameOrigin:origin]; // Why setFrameOrigin and cascadeTopLeftFromPoint are not animated?
initialSize.origin = origin;
[[wc.window animator] setFrame:initialSize display:YES];
}
[NSAnimationContext endGrouping];
Upvotes: 2
Reputation: 3028
This actually isn't a bug, but it has tripped me up a ton of times. You must set the completion handler before you invoke any animations.
Upvotes: 6
Reputation: 966
OK, it is a BUG and I file a bug report on it. The next version works perfectly
__block NSRect newPosition(initialSize);
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
[context setDuration:0.5f];
if (duplication) {
NSPoint origin = newPosition.origin;
origin.y += newPosition.size.height;
origin = [wc.window cascadeTopLeftFromPoint:origin];
origin.y -= newPosition.size.height;
//[[wc.window animator] setFrameOrigin:origin]; // Why setFrameOrigin and cascadeTopLeftFromPoint are not animated?
newPosition.origin = origin;
[[wc.window animator] setFrame:newPosition display:YES];
}
} completionHandler:^{
// This block will be invoked when all of the animations
// started above have completed or been cancelled.
if (edit)
[wc editDocument:self];
else
if (fullScreen)
[wc.window toggleFullScreen:self];
}];
Upvotes: 0