Остановка всех анимаций, выполняемых в другом потоке

У меня есть меню, в котором элементы появляются сразу друг за другом с интервалом в 3 секунды, я делаю это так:

for(UIButton *menuItem in menuItems){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        [menuItem setAlpha:1.0];
    }                             
}

Можно ли остановить анимацию посередине (например, при нажатии кнопки)? Я попытался просто установить все на альфа-версию 1.0, но, как и ожидалось, потоки продолжали работать и снова отображали элементы.

Буду признателен за любые идеи :)
Шай.


person Shai Mishali    schedule 06.11.2011    source источник
comment
Не имеет отношения к вашему вопросу, но теперь является потокобезопасным UIKit?   -  person Rog    schedule 16.11.2011
comment
Я действительно не знаю, что это значит :›   -  person Shai Mishali    schedule 16.11.2011
comment
Если что-то изменилось в iOS5 (а я не думаю, что они изменились), вы должны обновлять свой пользовательский интерфейс только через основной поток. Ваши очереди отправки обновляют пользовательский интерфейс в фоновом потоке, и это может вызвать проблемы с нестабильностью вашего приложения. Вот кое-что из официальной документации (внизу страницы) developer.apple.com/library/ios/#documentation/uikit/reference/   -  person Rog    schedule 16.11.2011
comment
Я понимаю. На самом деле я не мог найти лучшего способа делать то, что я хочу. (Я хочу отображать пункты меню с интервалом в 0,3 секунды). Любую другую технику вы бы использовали? Большое спасибо, что указали на это :)   -  person Shai Mishali    schedule 16.11.2011
comment
Ваш вопрос по-прежнему актуален и хорош. Я подумаю об этом и опубликую что-нибудь здесь, если смогу помочь.   -  person Rog    schedule 16.11.2011


Ответы (3)


Вы можете делать анимацию, используя блочную анимацию UIView, с набором delay:. Нить там не беспокоит.

Эти анимации можно прервать, запустив другую блочную анимацию с параметром UIViewAnimationOptionBeginFromCurrentStateset.

Для альфа-переходов это нормально, поскольку не имеет значения, какова текущая позиция анимации. Если вы перемещаете объекты, вы можете получить текущую позицию, запросив view.layer.presentationLayer, который содержит текущее состояние объекта. Для этого вам нужно будет импортировать фреймворк QuartzCore. Это также дает вам метод removeAllAnimations, который будет делать то, на что он похож, и переводит любое представление прямо в конечную точку любых анимаций, которые он ожидает или активен.

person jrturton    schedule 16.11.2011
comment
Проблема в том, что я не просто играю в альфу, я также играю звук с CocoDenshion. Попробую ваш метод и посмотрю, работает ли он. Спасибо чувак :) - person Shai Mishali; 16.11.2011
comment
следующий код показывает все элементы одновременно, а не с задержкой по какой-то причине: pastebin.com/dVEzCEWr - person Shai Mishali; 16.11.2011
comment
Блок завершения не выполняется до конца анимации. Увеличьте i в вашем цикле for, прежде чем будет установлена ​​​​каждая анимация. Я собирался добавить, что вы можете воспроизводить свой звук в блоке завершения, если анимация прерывается, параметр BOOL будет НЕТ, поэтому вы знаете, что звук не воспроизводится. - person jrturton; 16.11.2011
comment
Я действительно не понял, почему увеличение i в блоке завершения неправильно, поскольку мне нужно увеличить его на 1 только после окончания анимации, нет? В любом случае, ваше решение сработало отлично, спасибо за вашу помощь :) - person Shai Mishali; 16.11.2011
comment
Это позволяет мне дать награду только через 10 часов, так что ... :) извините заранее - person Shai Mishali; 16.11.2011
comment
Я могу подождать! Это неправильно в блоке завершения, потому что он не выполняется до тех пор, пока анимация не завершится, но вы ставите в очередь все анимации за один раз, поэтому значение i одинаково для каждой анимации, которую вы запускаете. Итак, вам нужно увеличивать его между вызовами, чтобы запустить каждую анимацию. Это, вероятно, выходит за рамки к тому времени, когда оно выполняется в блоке завершения... - person jrturton; 16.11.2011

Я не думаю, что вы можете остановить уже запланированные анимации. Но вы можете установить переменную экземпляра с флагом BOOL, указывающим, была ли уже нажата кнопка или нет.

Например, предположим, что целью вашей кнопки является метод buttonTapped.

Инициализируйте свой флаг на NO.

- (id)init {
    if (self = [super init]) {
        buttonAlreadyTapped = NO;
    }

    return self;
}

В целях вашей кнопки установите флаг YES.

- (void)buttonTapped {
    self.buttonAlreadyTapped = YES;
}

И изменяйте alpha только в том случае, если установлен флаг NO.

for (NSInteger i = 1; i <= [menuItems count]; i++) {        
    UIButton *menuItem = [menuItems objectAtIndex:i-1];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        if (!self.buttonAlreadyTapped) {
            menuItem.alpha = 1.0f;
        }
    });
}

Помните, что отправка сообщений на UIKit должна всегда выполняться в основном потоке.

for (NSInteger i = 1; i <= [menuItems count]; i++) {        
    UIButton *menuItem = [menuItems objectAtIndex:i-1];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (3 * i) * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        if (!self.buttonAlreadyTapped) {
            dispatch_async(dispatch_get_main_queue(), ^{
                menuItem.alpha = 1.0f;
            });
        }
    });
}
person pablasso    schedule 16.11.2011
comment
Я уже делаю это, но это не очень помогает. Я показываю 6 пунктов меню один за другим, и когда пользователь нажимает на один из них, я хочу остановить анимацию входа и показать их все, а также отменить анимацию в очереди. - person Shai Mishali; 16.11.2011
comment
+1 за совет по основному потоку, не знал об этом (dispatch_async в dispatch_after). Спасибо чувак :) - person Shai Mishali; 16.11.2011

Возможно, вы найдете ответ в этом ответе и, возможно, вы будете делать свои вещи по-другому.

person Serhii Mamontov    schedule 15.11.2011
comment
Этот комментарий в основном говорит мне, что подход dispatch_async не является правильным, он на самом деле не дает альтернативы, если мы не говорим о [NSThread PerformSelector], и даже тогда у меня не было бы ответа на мой вопрос выше (остановка анимации уже запланировано). - person Shai Mishali; 16.11.2011
comment
Кроме того, хотя я ценю ваше время, я не думаю, что предложение и ссылка считаются ответом. Должен быть комментарий в следующий раз. Еще раз, спасибо за ваше время, несмотря ни на что. - person Shai Mishali; 16.11.2011
comment
Без проблем. Я нахожу этот основной исходный код категории NSObject для задержанных и отмененных блоков gist.github.com/955123 Если вы будете использовать эти методы для создания экземпляров блоков и попытаетесь сохранить их, чем вы можете вызвать метод cancelBlock: для их отмены. - person Serhii Mamontov; 16.11.2011