Как иметь обработчик для повторения UIView animateWithDuration?
Я использую метод класса UIView animateWithDuration для повторения моей анимации вида. Как я могу иметь обработчик, который может быть использован, чтобы остановить эту анимацию позже? Например, повторная анимация начинается в одном методе, и мне нужно остановить ее позже из другого метода.
4 ответа
Вы можете сделать что-то вроде этого, если вы создали отмененное свойство. Как отмечено в комментариях, вызов startAnimation блока завершения должен быть заключен в асинхронный вызов, чтобы избежать переполнения стека. Обязательно замените "id" любым типом класса, который у вас есть.
- (void)startAnimation {
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
animations:^(void) {
//animate
}
completion:^(BOOL finished) {
if(!self.canceled) {
__weak id weakSelf = self;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[weakSelf startAnimation];
}];
}
}
];
}
Цель анимации - многократно анимировать отскок изображения. Когда нет необходимости останавливать его вручную, вам просто нужно установить три свойства (UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat)
и анимационный блок кода для перемещения изображения - self.image.center = CGPointMake(self.image.center.x, self.image.center.y+25);
Вот полный код анимации:
[UIView animateWithDuration:0.5 delay:0 options:( UIViewAnimationOptionCurveEaseIn |
UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat |
UIViewAnimationOptionAllowUserInteraction) animations:^{self.image.center =
CGPointMake(self.image.center.x, self.image.center.y+25);} completion:nil];
Вот и все. Но если вам нужно ручное управление, то требуется дополнительный код. Во-первых, согласно jaminguy, вам нужно иметь свойство BOOL для индикации цикла / остановки (self.playAnimationForImage) анимации и очищать отдельный метод с кодом анимации, который будет вызываться из другого места. Вот метод:
-(void)animateImageBounce{
[UIView animateWithDuration:0.5 delay:0 options:(
UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionAllowUserInteraction) animations:^{self.image.center =
CGPointMake(self.image.center.x, self.image.center.y+25);} completion:^(BOOL finished){if
(finished && self.playAnimationForImage){
self.image.center = CGPointMake(self.image.center.x, self.image.center.y-25);
[self animateImageBounce];
}}];
и вот начало вызова анимации из некоторого метода
-(void)someMethod{
...
self.playAnimationForFingers = YES;
[self animateImageBounce];
}
Единственное, что я хотел бы отметить, это то, что при ручном управлении вам нужно сбросить center.y изображения обратно перед выполнением следующего рекурсивного вызова.
На самом деле, решение с рекурсивным вызовом для меня не сработало. Анимация начала вести себя странно: каждые 2- 3 цикла повторения анимации я получал разрывы анимации. После первой подпрыгивающей части предмета (перемещение предмета вниз) вторая часть (продвижение вверх) выполнялась практически мгновенно. Я думаю, это как-то связано с рекурсивным вызовом.
Поэтому я отказался использовать это. Решением было бы запустить анимацию с опциями автореверса и повтора и, в полном блоке, проверить наличие флага (self.playAnimationForFingers
) указывает на остановку анимации.
-(void)animateFingersForLevelCompleteScreen{
//fix: reset the place of bouncing fingers (starting place).
//Otherwise the fingers will slowly move to the bottom at every level.
//This resetting is not working when placed inside UIView
//animate complete event block
self.image.center = CGPointMake(10 + self.image.frame.size.width/2,
95 + self.image.frame.size.height/2);
[UIView animateWithDuration:0.5 delay:0
options:(UIViewAnimationOptionCurveEaseIn |
UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionRepeat |
UIViewAnimationOptionAllowUserInteraction)
animations:^{
self.image.center = CGPointMake(self.image.center.x,
self.image.center.y+25);
}
completion:^(BOOL finished){
/*finished not approapriate: finished will not be TRUE if animation
was interrupted. It is very likely to happen because animation repeats && */
if (!self.playAnimationForFingers){
[UIView setAnimationRepeatAutoreverses:NO];
}
}];
}
Вы можете использовать CABasicAnimation вместо этого.
CABasicAnimation *appDeleteShakeAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
appDeleteShakeAnimation.autoreverses = YES;
appDeleteShakeAnimation.repeatDuration = HUGE_VALF;
appDeleteShakeAnimation.duration = 0.2;
appDeleteShakeAnimation.fromValue = [NSNumber numberWithFloat:-degreeToRadian(5)];
appDeleteShakeAnimation.toValue=[NSNumber numberWithFloat:degreeToRadian(5)];
[self.layer addAnimation:appDeleteShakeAnimation forKey:@"appDeleteShakeAnimation"];
Тогда, когда вы хотите остановить это, вы можете просто позвонить
[self.layer removeAnimationForKey:@"appDeleteShakeAnimation"];