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


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

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


person Hofi    schedule 11.11.2014    source источник


Ответы (3)


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

person Mattie    schedule 09.02.2016

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

Если установлено ненулевое значение, завершение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];
person Mecki    schedule 23.05.2019

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

__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];
}];
person Hofi    schedule 11.11.2014