如何让处理程序重复 UIView animateWithDuration?

发布于 2024-11-25 17:02:55 字数 111 浏览 0 评论 0原文

我正在使用 UIView 类方法 animateWithDuration 来重复我的视图动画。我怎样才能拥有一个可用于稍后停止此动画的处理程序?例如,重复的动画在一种方法中启动,我需要稍后从另一种方法停止它。

I'm using UIView class method animateWithDuration for repeating my view animation. How can I have a handler that could be used to stop this animation later? For example, repeated animation starts in one method and I need to stop it later from another method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

国粹 2024-12-02 17:02:55

假设您已经创建了一个取消属性,您可以执行类似的操作。如注释中所述,完成块的 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];
                             }];
                         }
                     }
     ];
}

You could do something like this assuming you have created a canceled property. As noted in the comments the completion block's startAnimation call needs to be wrapped in an async call to avoid a stack overflow. Be sure to replace the "id" with whatever class type you actually have.

- (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];
                             }];
                         }
                     }
     ];
}
顾挽 2024-12-02 17:02:55

动画的目的是重复地动画图像的弹跳。当不用担心手动停止它时,您只需要设置三个属性(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 重置回来被执行。

The purpose of the animation is to repeatedly animate the bounce of an image. When there is no worry about manually stopping it then you just need to set three properties (UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat) and animation block code for moving the image - self.image.center = CGPointMake(self.image.center.x, self.image.center.y+25); Here is the full code of the animation:

[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];

That's it. But if you need a manual control then some additional code is required. First, according to jaminguy, you need to have a BOOL property for indication loop/stop (self.playAnimationForImage) the animation and clean separate method with animation code that would be called from elsewhere. Here is the method:

-(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];
  }}]; 

and here is the start of the animation call from some method

-(void)someMethod{
...
self.playAnimationForFingers = YES;
[self animateImageBounce];

}

The thing that I would like to note is that, in manual control, you need to reset the center.y of the image back right before next recursive call is performed.

沧笙踏歌 2024-12-02 17:02:55

实际上,递归调用的解决方案对我来说并不奏效。动画开始表现得很奇怪:每 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]; 
      }
  }];
}

Actually, the solution with recursive call didn't worked out for me. The animation started to behave weirdly: every 2- 3 animatation repeat cycle I got animation breaks. After the first bouncing part of item (moving item down) the second part (moving up) was performing almost instantly. I thing it has something to do with the recursive call.

Therefore, I refused to use that. The solution would be to start the animation with autoreverse and repeat options and, in complete block, to check if a flag (self.playAnimationForFingers) indicates to stop the animation.

-(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]; 
      }
  }];
}
小草泠泠 2024-12-02 17:02:55

你可以使用 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"];

U can make use of CABasicAnimation instead.

    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"];

Then when u want to stop it you can just call

[self.layer removeAnimationForKey:@"appDeleteShakeAnimation"];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文