Почему NSAnimationContext завершение Handler не работает (иногда)?


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

Что мне здесь не хватает?

2 ответа

Это на самом деле не ошибка, но это сбило меня с толку множество раз. Вы должны установить обработчик завершения, прежде чем вызывать анимацию.

Проверьте документацию completionHandler:

Если задано значение, отличное от nil, контекст завершения Handler гарантированно будет вызван в основном потоке, как только все анимации, впоследствии добавленные в текущую группировку NSAnimationContext, будут завершены или отменены.

Источник: https://developer.apple.com/documentation/appkit/nsanimationcontext/1531132-completionhandler?language=objc

Обработчик завершения влияет только на анимацию, добавленную после того, как обработчик завершения был установлен.

В конце также говорится:

Если никакие анимации не добавляются до завершения текущей группировки или если для параметраручки установлено другое значение, обработчик будет вызван немедленно.

В вашем случае анимация не добавляется между установкой обработчика завершения и концом текущей группировки, поэтому ваш обработчик завершения вызывается немедленно.

Правильный код будет:

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

ОК, это ошибка, и я подаю отчет об ошибке на нем. Следующая версия работает отлично

__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];
}];
Другие вопросы по тегам