Как иметь обработчик для повторения UIView animateWithDuration? - PullRequest
2 голосов
/ 20 июля 2011

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

Ответы [ 4 ]

8 голосов
/ 22 июля 2011

Цель анимации - многократно анимировать отскок изображения. Когда нет необходимости останавливать его вручную, вам просто нужно установить три свойства (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 для индикации loop / stop (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 изображения обратно перед выполнением следующего рекурсивного вызова.

8 голосов
/ 20 июля 2011

Вы можете сделать что-то подобное, если вы создали свойство отменено . Как отмечено в комментариях, вызов 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];
                             }];
                         }
                     }
     ];
}
3 голосов
/ 28 июля 2011

На самом деле решение с рекурсивным вызовом у меня не сработало. Анимация начала вести себя странно: каждые 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]; 
      }
  }];
}
0 голосов
/ 06 февраля 2013

U может вместо этого использовать 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"];
...