为啥 NSAnimationContext completionHandler 不起作用(有时)?

Posted

技术标签:

【中文标题】为啥 NSAnimationContext completionHandler 不起作用(有时)?【英文标题】:Why NSAnimationContext completionHandler does not work (sometimes)?为什么 NSAnimationContext completionHandler 不起作用(有时)? 【发布时间】:2014-11-11 11:00:46 【问题描述】:

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

在这种情况下,完成块已执行,但不幸的是不等待窗口重新定位完成,而是立即打开窗口的编辑表并将它们一起移动。

最奇怪的是,在同一个源文件上面的几行相同类型的完成块工作正常:-O

我在这里错过了什么?

【问题讨论】:

【参考方案1】:

这实际上不是一个错误,但它让我绊倒了很多次。您必须调用任何动画之前设置完成处理程序。

【讨论】:

【参考方案2】:

查看completionHandler的文档:

如果设置为非零值,则保证在所有随后添加到当前 NSAnimationContext 分组的动画都已完成或被取消后,在主线程上调用上下文的 completionHandler。

来源:https://developer.apple.com/documentation/appkit/nsanimationcontext/1531132-completionhandler?language=objc

完成处理程序只影响完成处理程序设置后添加的动画。

最后它还说:

如果在当前分组结束之前没有添加动画——或者completionHandler设置为不同的值——处理程序将立即被调用。

在您的情况下,在设置完成处理程序和当前分组结束之间没有添加动画,因此您的完成处理程序会立即被调用。

正确的代码是:

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

【讨论】:

【参考方案3】:

好的,这是一个错误,我提交了一个错误报告。下一个版本完美运行

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

【讨论】:

以上是关于为啥 NSAnimationContext completionHandler 不起作用(有时)?的主要内容,如果未能解决你的问题,请参考以下文章

减慢或暂停 NSAnimationContext

未使用 NSAnimationContext 调用 CAAnimation animationDidStop

Swift MacOS NSAnimationContext 不遵循其持续时间

带有布局约束和 NSAnimationContext 的动画不正确

为啥 Iframe 不适用于 yahoo.com

为啥包名称通常以“com”开头[重复]