2015-02-23 2 views
9

Я запускаю эту анимацию при взаимодействии с пользователем, и иногда анимация может быть запущена снова до завершения текущей анимации. Мне бы хотелось сделать это, чтобы отменить предыдущую анимацию и продолжить ее с новой.UIView animateWithDuration завершение = YES, несмотря на отмену?

[UIView animateWithDuration:duration 
         delay:0 
        options:UIViewAnimationOptionBeginFromCurrentState 
       animations:^{ 
        self.bounds = bounds; 
       } 
       completion:^(BOOL finished) { 
        if (finished) { 
         // Do some cleanup after animating. 
        } 
       }]; 

Визуально это похоже на работу, но в моем завершение блока я сказал, что он закончил в обоих случаях, что вызывает код очистки запустить преждевременно. Таким образом, первый блок завершения анимации запускается сразу после запуска второго, с завершенным = YES. Я ожидал, что у него будет готовое значение NO, а второе (после его завершения) будет иметь YES.

Есть ли способ узнать, завершена ли анимация или была ли она отменена другим?

Sidenote: Я пытался делать то же анимацию с CABasicAnimation, а затем я закончу = NO в первый раз и YES во второй раз, так что поведение я получаю, кажется, быть специфическими для animateWithDuration.

Вот GIF, показывающий приведенный выше код в действии с продолжительностью 10 и блок завершения, обновляющий метку. Как вы можете видеть, finished является YES каждый раз, когда анимация будет перезапущен с animateWithDuration вызова:

ответ

11

Так я это исследовал дальше, и я думаю, что это IOS 8 конкретная вещь, из-за того, как анимация теперь Добавка по умолчанию, что означает, что анимация будет продолжаться и добавлять друг к другу, а не отменять.

В моем поиске Найден a WWDC session called "Building Interruptible and Responsive Interactions", который рассказывает об этом. В ходе сеанса они утверждают, что анимация будет завершена в одно и то же время, но это не так в моем тестировании (см. GIF в вопросе). Обходной путь, предложенный в сеансе, заключается в том, чтобы поддерживать счетчик, сколько раз запускалась анимация против завершенных и выполняла действия после анимации, когда счетчик достигает нуля. Это немного хаки, но работает. Вот код, вопрос с поправкой на это:

// Add this property to your class. 
self.runningAnimations++; 
[UIView animateWithDuration:duration 
         delay:0 
        options:UIViewAnimationOptionBeginFromCurrentState 
       animations:^{ 
        self.bounds = bounds; 
       } 
       completion:^(BOOL finished) { 
        if (--self.runningAnimations == 0) { 
         // Do some cleanup after animating. 
        } 
       }]; 

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

+0

Спасибо, это помогло мне исправить мои сбои в анимации из-за того, что закончен всегда быть истинным на iOS 9. – malhal

+0

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

+0

Это то, что я тоже делал (iOS 9.3, Swift)! Спасибо за помощь. –

0

Какой метод вы пытались отменить анимацию?

theView_ = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
[theView_ setBackgroundColor:[UIColor magentaColor]]; 
[self.view addSubview:theView_]; 

[UIView animateWithDuration:10 
       animations:^{ 
        theView_.frame = CGRectMake(200, 200, 50, 50); 
       } completion:^(BOOL finished) { 
        NSLog(@"done : %@", @(finished)); 
        if(finished) { 

        } 
        else { 

        } 
       }]; 

[self performSelector:@selector(cancelAnimation) withObject:nil afterDelay:2]; 

Метод cancelAnimation, как показано ниже:

- (void)cancelAnimation { 
    NSLog(@"cancel"); 
    [theView_.layer removeAllAnimations]; 

}

finished вернется false когда анимация отменен.

журнала сообщений, как и ожидалось:

2015-02-23 14:13:58.625 TestPrj[47338:6070317] cancel 
2015-02-23 14:13:58.626 TestPrj[47338:6070317] done : 0 
+1

Да, но вызов 'removeAllAnimations' мгновенно помещает представление в его конечное состояние. Я хочу отменить первую анимацию со вторым вызовом 'animateWithDuration'.Второй вызов явно отменил его (блок 'complete' вызывается напрямую), но значение' finished' 'YES' вместо' NO', поэтому я не могу различить отмененную анимацию и анимацию, которая на самом деле законченный. – Blixt

+0

@Blixt То, что вы хотите реализовать, - это анимация паузы/возобновления с блочным анимационным методом. Вы уже видели этот http://stackoverflow.com/questions/15119839/uiview-animation-block-pause-both-the-animation-and-the-completion-code? – Ryan

+0

Это аккуратно, но мне действительно нужно заменить анимацию, так как анимация «границ» переходит в произвольную позицию на основе ввода пользователя. Есть ли способ заменить «toValue» анимации, а не приостанавливать ее? – Blixt

Смежные вопросы