【问题标题】:UIView Infinite 360 degree rotation animation?UIView无限360度旋转动画?
【发布时间】:2012-04-08 08:25:25
【问题描述】:

我正在尝试将UIImageView 旋转 360 度,并查看了一些在线教程。如果没有 UIView 停止或跳到新位置,我无法让它们中的任何一个工作。

  • 我怎样才能做到这一点?

我最近尝试的是:

[UIView animateWithDuration:1.0
                      delay:0.0
                    options:0
                 animations:^{
                     imageToMove.transform = CGAffineTransformMakeRotation(M_PI);
                 } 
                 completion:^(BOOL finished){
                     NSLog(@"Done!");
                 }];

但如果我使用 2*pi,它根本不会移动(因为它的位置相同)。如果我尝试只做 pi(180 度),它可以工作,但如果我再次调用该方法,它会向后旋转。

编辑

[UIView animateWithDuration:1.0
                      delay:0.0
                    options:0
                 animations:^{
                     [UIView setAnimationRepeatCount:HUGE_VALF];
                     [UIView setAnimationBeginsFromCurrentState:YES];
                     imageToMove.transform = CGAffineTransformMakeRotation(M_PI);
                 } 
                 completion:^(BOOL finished){
                     NSLog(@"Done!");
                 }];

也不行。它转到180 度,停顿片刻,然后在重新开始之前重置回0 度。

【问题讨论】:

    标签: ios objective-c animation uiview core-animation


    【解决方案1】:

    使用直角转弯,并逐渐增加转弯。

    void (^block)() = ^{
        imageToMove.transform = CGAffineTransformRotate(imageToMove.transform, M_PI / 2);
    }
    
    void (^completion)(BOOL) = ^(BOOL finished){
        [UIView animateWithDuration:1.0
                              delay:0.0
                            options:0
                         animations:block
                         completion:completion];
    }
    
    completion(YES);
    

    【讨论】:

    • 我对块很陌生,但是这种方法会抛出错误“不兼容的块指针类型将'void(^const__strong()'发送到'void(^)(BOOL)'类型的参数。我试过了将我的问题代码中的旋转方法更改为 imageToMove.transform = CGAffineTransformRotate(imageToMove.transform, M_PI / 2); 您使用了,并且动画仍然有轻微的延迟,并在下一回合之前重置。
    【解决方案2】:

    找到了一个非常适合我的方法(我对其进行了一些修改):iphone UIImageView rotation

    #import <QuartzCore/QuartzCore.h>
    
    - (void) runSpinAnimationOnView:(UIView*)view duration:(CGFloat)duration rotations:(CGFloat)rotations repeat:(float)repeat {
        CABasicAnimation* rotationAnimation;
        rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
        rotationAnimation.duration = duration;
        rotationAnimation.cumulative = YES;
        rotationAnimation.repeatCount = repeat ? HUGE_VALF : 0;
    
        [view.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    }
    

    【讨论】:

    • #import
    • 添加 QuartzCore.framework Project->Build Phases->Link Binaries
    • 这是适用于 iOS 3.0 及更低版本的正确代码,但对于新程序员和新项目,Apple 现在在 Docs 中警告用户远离这些方法,@Nate 代码使用 Apple 现在更喜欢的基于块的动画
    • @cvsguimaraes 来自文档:“确定属性的值是否是上一个重复周期结束时的值,加上当前重复周期的值。”
    • 这可能会帮助一些人,[view.layer removeAllAnimations]; 在需要时停止动画。
    【解决方案3】:

    感谢 Richard J. Ross III 的想法,但我发现他的代码并不是我所需要的。我相信options 的默认值是给你UIViewAnimationOptionCurveEaseInOut,这在连续动画中看起来不正确。另外,我添加了一个检查,以便在需要时可以在偶数四分之一转时停止动画(不是无限,而是无限期持续时间),并进行加速斜坡在前 90 度期间向上,在最后 90 度期间减速(请求停止后):

    // an ivar for your class:
    BOOL animating;
    
    - (void)spinWithOptions:(UIViewAnimationOptions)options {
       // this spin completes 360 degrees every 2 seconds
       [UIView animateWithDuration:0.5
                             delay:0
                           options:options
                        animations:^{
                           self.imageToMove.transform = CGAffineTransformRotate(imageToMove.transform, M_PI / 2);
                        }
                        completion:^(BOOL finished) {
                           if (finished) {
                              if (animating) {
                                 // if flag still set, keep spinning with constant speed
                                 [self spinWithOptions: UIViewAnimationOptionCurveLinear];
                              } else if (options != UIViewAnimationOptionCurveEaseOut) {
                                 // one last spin, with deceleration
                                 [self spinWithOptions: UIViewAnimationOptionCurveEaseOut];
                              }
                           }
                        }];
    }
    
    - (void)startSpin {
       if (!animating) {
          animating = YES;
          [self spinWithOptions: UIViewAnimationOptionCurveEaseIn];
       }
    }
    
    - (void)stopSpin {
        // set the flag to stop spinning after one last 90 degree increment
        animating = NO;
    }
    

    更新

    我添加了处理请求以再次开始旋转 (startSpin) 的功能,而前一次旋转正在结束(完成)。示例项目here on Github.

    【讨论】:

    • 使用这个,我注意到动画在每个 PI/2 角度(90 度)处有一个短暂的停顿,并且 CPU 使用率比使用 CABasicAnimation 选择的答案略有增加。 CABasicAnimation 方法产生完美流畅的动画。
    • @Dilip,将M_PI / 2 替换为- (M_PI / 2)。 (向右滚动代码以查看每一行的末尾)
    • @Dilip,我不知道您在代码中使用的持续时间。和我一样,每 90 度的 0.5 秒?如果是这样,我的代码不会让您停在 90 度旋转的 分数 处。它允许您在整个 90 度间隔处停止,但会增加一个额外的 90 度旋转,“缓和”。因此,在上面的代码中,如果您在 0.35 秒后调用 stopSpin,它将再旋转 0.65 秒,并在总旋转 180 度时停止。如果您有更详细的问题,您可能应该提出一个新问题。随意链接到这个答案。
    • 你看到了什么,@MohitJethwa?我有一个使用它的应用程序,它在 iOS 8.1 上仍然适用于我。
    • @Hemang,当然,但这不是这个问题。如果这是你想要做的,我会发布一个新问题。
    【解决方案4】:

    您也可以使用 UIView 和块来制作相同类型的动画。这是一个可以任意角度旋转视图的类扩展方法。

    - (void)rotationWithDuration:(NSTimeInterval)duration angle:(CGFloat)angle options:(UIViewAnimationOptions)options
    {
        // Repeat a quarter rotation as many times as needed to complete the full rotation
        CGFloat sign = angle > 0 ? 1 : -1;
        __block NSUInteger numberRepeats = floorf(fabsf(angle) / M_PI_2);
        CGFloat quarterDuration = duration * M_PI_2 / fabs(angle);
    
        CGFloat lastRotation = angle - sign * numberRepeats * M_PI_2;
        CGFloat lastDuration = duration - quarterDuration * numberRepeats;
    
        __block UIViewAnimationOptions startOptions = UIViewAnimationOptionBeginFromCurrentState;
        UIViewAnimationOptions endOptions = UIViewAnimationOptionBeginFromCurrentState;
    
        if (options & UIViewAnimationOptionCurveEaseIn || options == UIViewAnimationOptionCurveEaseInOut) {
            startOptions |= UIViewAnimationOptionCurveEaseIn;
        } else {
            startOptions |= UIViewAnimationOptionCurveLinear;
        }
    
        if (options & UIViewAnimationOptionCurveEaseOut || options == UIViewAnimationOptionCurveEaseInOut) {
            endOptions |= UIViewAnimationOptionCurveEaseOut;
        } else {
            endOptions |= UIViewAnimationOptionCurveLinear;
        }
    
        void (^lastRotationBlock)(void) = ^ {
            [UIView animateWithDuration:lastDuration 
                                  delay:0 
                                options:endOptions 
                             animations:^{
                                 self.transform = CGAffineTransformRotate(self.transform, lastRotation);
                             } 
                             completion:^(BOOL finished) {
                                 NSLog(@"Animation completed");   
                             }
             ];
        };
    
        if (numberRepeats) {
            __block void (^quarterSpinningBlock)(void) = ^{ 
                [UIView animateWithDuration:quarterDuration 
                                      delay:0 
                                    options:startOptions 
                                 animations:^{
                                     self.transform = CGAffineTransformRotate(self.transform, M_PI_2);
                                     numberRepeats--; 
                                 } 
                                 completion:^(BOOL finished) {
                                     if (numberRepeats > 0) {
                                         startOptions = UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear;
                                         quarterSpinningBlock();
                                     } else {
                                         lastRotationBlock();
                                     }NSLog(@"Animation completed");   
                                 }
                 ];
    
            };
    
            quarterSpinningBlock();
        } else {
            lastRotationBlock();
        }
    }
    

    【讨论】:

    • 这种方法(完成时的递归调用)是否适用于快速变化的动画?例如,持续时间约为。 1/30s 这样我就可以实时修改对象的旋转速度,例如对触摸做出反应?
    【解决方案5】:

    如果你想做的只是无休止地旋转图像,这很有效,而且非常简单:

    NSTimeInterval duration = 10.0f;
    CGFloat angle = M_PI / 2.0f;
    CGAffineTransform rotateTransform = CGAffineTransformRotate(imageView.transform, angle);
    
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionRepeat| UIViewAnimationOptionCurveLinear animations:^{
        imageView.transform = rotateTransform;
    } completion:nil];
    

    根据我的经验,这可以完美运行,但请确保您的图像能够围绕其中心旋转而没有任何偏移,否则图像动画会在绕到 PI 后“跳跃”。

    要改变旋转的方向,改变angle (angle *= -1) 的符号。

    更新 @AlexPretzlav 的评论让我重新审视了这一点,我意识到当我写这篇文章时,我正在旋转的图像沿垂直轴和水平轴镜像,这意味着图像确实只是在旋转90 度,然后重置,尽管它看起来就像它一直在继续旋转。

    所以,如果您的图像和我的一样,这会很好用,但是,如果图像不对称,您会注意到 90 度后“快速”回到原来的方向。

    要旋转非对称图像,最好使用接受的答案。

    如下所示,其中一种不太优雅的解决方案会真正旋转图像,但在重新启动动画时可能会出现明显的卡顿:

    - (void)spin
    {
        NSTimeInterval duration = 0.5f;
        CGFloat angle = M_PI_2;
        CGAffineTransform rotateTransform = CGAffineTransformRotate(self.imageView.transform, angle);
    
        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            self.imageView.transform = rotateTransform;
        } completion:^(BOOL finished) {
            [self spin];
        }];
    }
    

    您也可以像 @richard-j-ross-iii 建议的那样仅使用块来执行此操作,但是由于块正在捕获自身,因此您会收到保留循环警告:

    __block void(^spin)() = ^{
        NSTimeInterval duration = 0.5f;
        CGFloat angle = M_PI_2;
        CGAffineTransform rotateTransform = CGAffineTransformRotate(self.imageView.transform, angle);
    
        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            self.imageView.transform = rotateTransform;
        } completion:^(BOOL finished) {
            spin();
        }];
    };
    spin();
    

    【讨论】:

    • 这对我来说只旋转了 1/4 圈。
    • @AlexPretzlav 确保您在动画中设置了UIViewAnimationOptionRepeat options
    • 我做了,它旋转了 45°,然后通过跳回 0° 并再次旋转 45° 循环
    • 用关于为什么这个“有效”的新信息更新了我的答案
    【解决方案6】:

    上面 Nate 的回答非常适合停止和启动动画,并提供更好的控制。我很好奇为什么你的不工作而他的工作。我想在这里分享我的发现和一个更简单的代码版本,它可以连续动画 UIView 而不会停止。

    这是我使用的代码,

    - (void)rotateImageView
    {
        [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            [self.imageView setTransform:CGAffineTransformRotate(self.imageView.transform, M_PI_2)];
        }completion:^(BOOL finished){
            if (finished) {
                [self rotateImageView];
            }
        }];
    }
    

    我使用“CGAffineTransformRotate”而不是“CGAffineTransformMakeRotation”,因为前者返回的结果会随着动画的进行而保存。这将防止在动画期间跳转或重置视图。

    另一件事是不要使用'UIViewAnimationOptionRepeat',因为在动画开始重复之前,它会重置变换,使视图跳回其原始位置。不是重复,而是递归,以便变换永远不会重置为原始值,因为动画块实际上永远不会结束。

    最后一件事是,您必须以 90 度 (M_PI / 2) 的步长转换视图,而不是 360 或 180 度(2*M_PI 或 M_PI)。因为变换是作为正弦值和余弦值的矩阵乘法发生的。

    t' =  [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t
    

    因此,假设您使用 180 度变换,则 180 的余弦会产生 -1,每次都使视图变换方向相反(如果您将变换的弧度值更改为 M_PI,Note-Nate 的回答也会出现此问题)。 360 度变换只是要求视图保持在原来的位置,因此您根本看不到任何旋转。

    【讨论】:

    • 我的回答(以及由此得出的 Richard 的回答)的重点是使用 90 度 步长,以避免切换方向。 如果您确实想停止旋转,90 度的效果也相对较好,因为许多图像具有 180 度或 90 度对称性。
    • 是的,我只是想解释一下为什么要使用它:)
    • @nik 但是在那里设置断点后,我看到不会有堆栈溢出,因为系统调用了完成块,那时rotateImageView 已经完成。所以从这个意义上说,它并不是真正的递归。
    • 对于具有所需功能的小版本代码的好答案 +1。
    • 我非常感谢为什么不使用 UIViewAnimationOptionRepeat 的解释。
    【解决方案7】:

    我在repository 中找到了不错的代码,

    这是其中的代码,我根据我对速度的需要做了一些小改动:)

    UIImageView+Rotate.h

    #import <Foundation/Foundation.h>
    
    @interface UIImageView (Rotate)
    - (void)rotate360WithDuration:(CGFloat)duration repeatCount:(float)repeatCount;
    - (void)pauseAnimations;
    - (void)resumeAnimations;
    - (void)stopAllAnimations;
    @end
    

    UIImageView+Rotate.m

    #import <QuartzCore/QuartzCore.h>
    #import "UIImageView+Rotate.h"
    
    @implementation UIImageView (Rotate)
    
    - (void)rotate360WithDuration:(CGFloat)duration repeatCount:(float)repeatCount
    {
    
        CABasicAnimation *fullRotation;
        fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        fullRotation.fromValue = [NSNumber numberWithFloat:0];
        //fullRotation.toValue = [NSNumber numberWithFloat:(2*M_PI)];
        fullRotation.toValue = [NSNumber numberWithFloat:-(2*M_PI)]; // added this minus sign as i want to rotate it to anticlockwise
        fullRotation.duration = duration;
        fullRotation.speed = 2.0f;              // Changed rotation speed
        if (repeatCount == 0)
            fullRotation.repeatCount = MAXFLOAT;
        else
            fullRotation.repeatCount = repeatCount;
    
        [self.layer addAnimation:fullRotation forKey:@"360"];
    }
    
    //Not using this methods :)
    
    - (void)stopAllAnimations
    {
    
        [self.layer removeAllAnimations];
    };
    
    - (void)pauseAnimations
    {
    
        [self pauseLayer:self.layer];
    }
    
    - (void)resumeAnimations
    {
    
        [self resumeLayer:self.layer];
    }
    
    - (void)pauseLayer:(CALayer *)layer
    {
    
        CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
        layer.speed = 0.0;
        layer.timeOffset = pausedTime;
    }
    
    - (void)resumeLayer:(CALayer *)layer
    {
    
        CFTimeInterval pausedTime = [layer timeOffset];
        layer.speed = 1.0;
        layer.timeOffset = 0.0;
        layer.beginTime = 0.0;
        CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
        layer.beginTime = timeSincePause;
    }
    
    @end
    

    【讨论】:

    • @BreadicalMD,数学就像编程,你可以用多种方式做同样的事情。这并不意味着只有一种方法是正确的,而另一种则不是。是的,每种方式都有一些优点和缺点,但这并不意味着你可以质疑某人的编程方法,你可以建议这种方法的缺点和你的方法的优点。这条评论真的很冒犯,你不应该添加这样的评论。
    • 很抱歉冒犯了 Dilip,但写 2*M_PI 客观上比 ((360 * M_PI)/180) 更清楚,写后者表明对主题缺乏了解手。
    • @BreadicalMD 不用担心,但这是个好建议,我已经更新了我的代码。谢谢。
    【解决方案8】:

    这就是我向正确方向旋转 360 度的方式。

    [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionRepeat|UIViewAnimationOptionCurveLinear
                         animations:^{
                             [imageIndView setTransform:CGAffineTransformRotate([imageIndView transform], M_PI-0.00001f)];
                         } completion:nil];
    

    【讨论】:

      【解决方案9】:

      在 Swift 中,您可以使用以下代码进行无限旋转:

      斯威夫特 4

      extension UIView {
          private static let kRotationAnimationKey = "rotationanimationkey"
      
          func rotate(duration: Double = 1) {
              if layer.animation(forKey: UIView.kRotationAnimationKey) == nil {
                  let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
      
                  rotationAnimation.fromValue = 0.0
                  rotationAnimation.toValue = Float.pi * 2.0
                  rotationAnimation.duration = duration
                  rotationAnimation.repeatCount = Float.infinity
      
                  layer.add(rotationAnimation, forKey: UIView.kRotationAnimationKey)
              }
          }
      
          func stopRotating() {
              if layer.animation(forKey: UIView.kRotationAnimationKey) != nil {
                  layer.removeAnimation(forKey: UIView.kRotationAnimationKey)
              }
          }
      }
      

      斯威夫特 3

      let kRotationAnimationKey = "com.myapplication.rotationanimationkey" // Any key
      
      func rotateView(view: UIView, duration: Double = 1) {
          if view.layer.animationForKey(kRotationAnimationKey) == nil {
              let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
      
              rotationAnimation.fromValue = 0.0
              rotationAnimation.toValue = Float(M_PI * 2.0)
              rotationAnimation.duration = duration
              rotationAnimation.repeatCount = Float.infinity
      
              view.layer.addAnimation(rotationAnimation, forKey: kRotationAnimationKey)
          }
      }
      

      停止就像:

      func stopRotatingView(view: UIView) {
          if view.layer.animationForKey(kRotationAnimationKey) != nil {
              view.layer.removeAnimationForKey(kRotationAnimationKey)
          }
      }
      

      【讨论】:

      • 什么是 kRotationAnimationKey?
      • 它是一个常量字符串键,可以帮助您识别和搜索动画。它可以是您想要的任何字符串。在删除过程中,可以看到该动画被搜索到,然后被该键删除。
      • 是字符串还是特定的东西?
      • 对不起,回答晚了,但是可以,它可以是任何字符串。
      • // 答案中的任意键
      【解决方案10】:

      我开发了一个闪亮的动画框架,可以节省你的时间! 使用它可以很容易地创建这个动画:

      private var endlessRotater: EndlessAnimator!
      override func viewDidAppear(animated: Bool) 
      {
          super.viewDidAppear(animated)
          let rotationAnimation = AdditiveRotateAnimator(M_PI).to(targetView).duration(2.0).baseAnimation(.CurveLinear)
          endlessRotater = EndlessAnimator(rotationAnimation)
          endlessRotater.animate()
      }
      

      要停止此动画,只需将nil 设置为endlessRotater

      有兴趣的可以看看:https://github.com/hip4yes/Animatics

      【讨论】:

        【解决方案11】:

        如果有人想要 nates 的解决方案,但要快速,那么这里有一个粗略的 swift 翻译:

        class SomeClass: UIViewController {
        
            var animating : Bool = false
            @IBOutlet weak var activityIndicatorImage: UIImageView!
        
            func startSpinning() {
                if(!animating) {
                    animating = true;
                    spinWithOptions(UIViewAnimationOptions.CurveEaseIn);
                }
            }
        
            func stopSpinning() {
                animating = false
            }
        
            func spinWithOptions(options: UIViewAnimationOptions) {
                UIView.animateWithDuration(0.5, delay: 0.0, options: options, animations: { () -> Void in
                    let val : CGFloat = CGFloat((M_PI / Double(2.0)));
                    self.activityIndicatorImage.transform = CGAffineTransformRotate(self.activityIndicatorImage.transform,val)
                }) { (finished: Bool) -> Void in
        
                    if(finished) {
                        if(self.animating){
                            self.spinWithOptions(UIViewAnimationOptions.CurveLinear)
                        } else if (options != UIViewAnimationOptions.CurveEaseOut) {
                            self.spinWithOptions(UIViewAnimationOptions.CurveEaseOut)
                        }
                    }
        
                }
            }
        
            override func viewDidLoad() {
                startSpinning()
            }
        }
        

        【讨论】:

          【解决方案12】:

          我对已检查解决方案中的 Swift 扩展的贡献:

          Swift 4.0

          extension UIView{
              func rotate() {
                  let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
                  rotation.toValue = NSNumber(value: Double.pi * 2)
                  rotation.duration = 1
                  rotation.isCumulative = true
                  rotation.repeatCount = Float.greatestFiniteMagnitude
                  self.layer.add(rotation, forKey: "rotationAnimation")
              }
          }
          

          已弃用:

          extension UIView{
              func rotate() {
                  let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
                  rotation.toValue = NSNumber(double: M_PI * 2)
                  rotation.duration = 1
                  rotation.cumulative = true
                  rotation.repeatCount = FLT_MAX
                  self.layer.addAnimation(rotation, forKey: "rotationAnimation")
              }
          }
          

          【讨论】:

          • 重复次数可以使用.infinity
          【解决方案13】:

          @ram 的answer 真的很有帮助。这是答案的 Swift 版本。

          斯威夫特 2

          private func rotateImageView() {
          
              UIView.animateWithDuration(1, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                  self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, CGFloat(M_PI_2))
                  }) { (finished) -> Void in
                      if finished {
                          self.rotateImageView()
                      }
              }
          }
          

          斯威夫特 3,4,5

          private func rotateImageView() {
          
              UIView.animate(withDuration: 1, delay: 0, options: UIView.AnimationOptions.curveLinear, animations: { () -> Void in
                  self.imageView.transform = self.imageView.transform.rotated(by: .pi / 2)
              }) { (finished) -> Void in
                  if finished {
                      self.rotateImageView()
                  }
              }
          }
          

          【讨论】:

          • 如何停止旋转?
          • 你放个flag怎么样?所以,也许你有一个停止动画的函数:var stop = falseprivate func stopRotation() { stop = true } 然后,在if finished {...}内部:if finished { if stop { return} self.rotateImageView() }
          • 谢谢,我也是这么做的。感谢您的回复。
          【解决方案14】:

          斯威夫特:

          func runSpinAnimationOnView(view:UIView , duration:Float, rotations:Double, repeatt:Float ) ->()
              {
                  let rotationAnimation=CABasicAnimation();
          
                  rotationAnimation.keyPath="transform.rotation.z"
          
                  let toValue = M_PI * 2.0 * rotations ;
          
          
                  // passing it a float
                  let someInterval = CFTimeInterval(duration)
          
                  rotationAnimation.toValue=toValue;
                  rotationAnimation.duration=someInterval;
                  rotationAnimation.cumulative=true;
                  rotationAnimation.repeatCount=repeatt;
                  view.layer.addAnimation(rotationAnimation, forKey: "rotationAnimation")
          
          
              }
          

          【讨论】:

            【解决方案15】:

            这对我有用:

            [UIView animateWithDuration:1.0
                            animations:^
            {
                self.imageView.transform = CGAffineTransformMakeRotation(M_PI);
                self.imageView.transform = CGAffineTransformMakeRotation(0);
            }];
            

            【讨论】:

            • 它不会无限次发生!
            【解决方案16】:

            这是我作为 UIView 扩展的快速解决方案。它可以被认为是对任何 UIImageView 上的 UIActivityIndi​​cator 行为的模拟。

            import UIKit
            
            extension UIView
            {
            
                /**
                Starts rotating the view around Z axis.
            
                @param duration Duration of one full 360 degrees rotation. One second is default.
                @param repeatCount How many times the spin should be done. If not provided, the view will spin forever.
                @param clockwise Direction of the rotation. Default is clockwise (true).
                 */
                func startZRotation(duration duration: CFTimeInterval = 1, repeatCount: Float = Float.infinity, clockwise: Bool = true)
                {
                    if self.layer.animationForKey("transform.rotation.z") != nil {
                        return
                    }
                    let animation = CABasicAnimation(keyPath: "transform.rotation.z")
                    let direction = clockwise ? 1.0 : -1.0
                    animation.toValue = NSNumber(double: M_PI * 2 * direction)
                    animation.duration = duration
                    animation.cumulative = true
                    animation.repeatCount = repeatCount
                    self.layer.addAnimation(animation, forKey:"transform.rotation.z")
                }
            
            
                /// Stop rotating the view around Z axis.
                func stopZRotation()
                {
                    self.layer.removeAnimationForKey("transform.rotation.z")
                }
            
            }
            

            【讨论】:

              【解决方案17】:

              创建动画

              - (CABasicAnimation *)spinAnimationWithDuration:(CGFloat)duration clockwise:(BOOL)clockwise repeat:(BOOL)repeats
              {
                  CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
                  anim.toValue = clockwise ? @(M_PI * 2.0) : @(M_PI * -2.0);
                  anim.duration = duration;
                  anim.cumulative = YES;
                  anim.repeatCount = repeats ? CGFLOAT_MAX : 0;
                  return anim;
              }
              

              将它添加到这样的视图中

              CABasicAnimation *animation = [self spinAnimationWithDuration:1.0 clockwise:YES repeat:YES];
              [self.spinningView.layer addAnimation:animation forKey:@"rotationAnimation"];
              

              这个答案有何不同?如果您的大多数函数返回对象而不是在这里和那里操作一些对象,那么您将拥有更清晰的代码。

              【讨论】:

                【解决方案18】:

                对于 xamarin ios:

                public static void RotateAnimation (this UIView view, float duration=1, float rotations=1, float repeat=int.MaxValue)
                {
                    var rotationAnimation = CABasicAnimation.FromKeyPath ("transform.rotation.z");
                    rotationAnimation.To = new NSNumber (Math.PI * 2.0 /* full rotation*/ * 1 * 1);
                    rotationAnimation.Duration = 1;
                    rotationAnimation.Cumulative = true;
                    rotationAnimation.RepeatCount = int.MaxValue;
                    rotationAnimation.RemovedOnCompletion = false;
                    view.Layer.AddAnimation (rotationAnimation, "rotationAnimation");
                }
                

                【讨论】:

                  【解决方案19】:

                  斯威夫特 3:

                   var rotationAnimation = CABasicAnimation()
                       rotationAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
                       rotationAnimation.toValue = NSNumber(value: (M_PI * 2.0))
                       rotationAnimation.duration = 2.0
                       rotationAnimation.isCumulative = true
                       rotationAnimation.repeatCount = 10.0
                       view.layer.add(rotationAnimation, forKey: "rotationAnimation")
                  

                  【讨论】:

                    【解决方案20】:

                    Swift3 版本:

                    extension UIView {
                    
                        func startRotate() {
                            let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
                            rotation.fromValue = 0
                            rotation.toValue = NSNumber(value: M_PI * 2)
                            rotation.duration = 2
                            rotation.isCumulative = true
                            rotation.repeatCount = FLT_MAX
                            self.layer.add(rotation, forKey: "rotationAnimation")
                        }
                    
                        func stopRotate() {
                            self.layer.removeAnimation(forKey: "rotationAnimation")
                        }
                    }
                    

                    记得在viewWillAppear 中调用startRotate 而不是在viewDidLoad 中。

                    【讨论】:

                      【解决方案21】:
                      let val = CGFloat(M_PI_2)
                      
                      UIView.animate(withDuration: 1, delay: 0, options: [.repeat, .curveLinear], animations: {
                              self.viewToRotate.transform = self.viewToRotate.transform.rotated(by: val)
                      })
                      

                      【讨论】:

                        【解决方案22】:

                        使用 UIView 执行 360 度动画有以下不同的方式。

                        使用 CABasicAnimation

                        var rotationAnimation = CABasicAnimation()
                        rotationAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
                        rotationAnimation.toValue = NSNumber(value: (Double.pi))
                        rotationAnimation.duration = 1.0
                        rotationAnimation.isCumulative = true
                        rotationAnimation.repeatCount = 100.0
                        view.layer.add(rotationAnimation, forKey: "rotationAnimation")
                        


                        这是处理开始和停止旋转操作的 UIView 的扩展函数:

                        extension UIView {
                        
                            // Start rotation
                            func startRotation() {
                                let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
                                rotation.fromValue = 0
                                rotation.toValue = NSNumber(value: Double.pi)
                                rotation.duration = 1.0
                                rotation.isCumulative = true
                                rotation.repeatCount = FLT_MAX
                                self.layer.add(rotation, forKey: "rotationAnimation")
                            }
                        
                            // Stop rotation
                            func stopRotation() {
                                self.layer.removeAnimation(forKey: "rotationAnimation")
                            }
                        }
                        


                        现在使用 UIView.animation 闭包:

                        UIView.animate(withDuration: 0.5, animations: { 
                              view.transform = CGAffineTransform(rotationAngle: (CGFloat(Double.pi)) 
                        }) { (isAnimationComplete) in
                            // Animation completed 
                        }
                        

                        【讨论】:

                          【解决方案23】:

                          我认为你最好添加一个UIVIew 类别:

                          #import <QuartzCore/QuartzCore.h>
                          #import "UIView+Rotate.h"
                          

                          实现 UIView(旋转)

                          • (void)remrotate360WithDuration:(CGFloat)duration repeatCount: (float)repeatCount
                            {
                                CABasicAnimation *fullRotation;
                                fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
                                fullRotation.fromValue = [NSNumber numberWithFloat:0];
                                fullRotation.toValue = [NSNumber numberWithFloat:(2*M_PI)];
                                // fullRotation.toValue = [NSNumber numberWithFloat:-(2*M_PI)]; // added this minus sign as i want to rotate it to anticlockwise
                                fullRotation.duration = duration;
                                fullRotation.speed = 2.0f; // Changed rotation speed
                                if (repeatCount == 0)
                                    fullRotation.repeatCount = MAXFLOAT;
                                else
                                    fullRotation.repeatCount = repeatCount;
                            
                                [self.layer addAnimation:fullRotation forKey:@"360"];
                            }
                            

                          不使用这种方法:)

                          • (void)remstopAllAnimations
                            {
                                [self.layer removeAllAnimations];
                            };
                            
                          • (void)rempauseAnimations
                            {
                                [self rempauseLayer:self.layer];
                            }
                            
                          • (void)remresumeAnimations
                            {
                                [self remresumeLayer:self.layer];
                            }
                            
                          • (void)rempauseLayer:(CALayer *)layer
                            {
                                CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
                                layer.speed = 0.0;
                                layer.timeOffset = pausedTime;
                            }
                            
                          • (void)remresumeLayer:(CALayer *)layer
                            {
                                CFTimeInterval pausedTime = [layer timeOffset];
                                layer.speed = 1.0;
                                layer.timeOffset = 0.0;
                                layer.beginTime = 0.0;
                                CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
                                layer.beginTime = timeSincePause;
                            }
                            

                          【讨论】:

                          • 干得好。我只想评论 UIImageView 类别。还是谢谢大家。
                          【解决方案24】:

                          斯威夫特 4

                          func rotateImage(image: UIImageView) {
                                  UIView.animate(withDuration: 1, animations: {
                                      image.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
                                      image.transform = CGAffineTransform.identity
                                  }) { (completed) in
                                      self.rotateImage()
                                  }
                              }
                          

                          Ref

                          【讨论】:

                            【解决方案25】:

                            Swift 4.0

                            func rotateImageView()
                            {
                                UIView.animate(withDuration: 0.3, delay: 0, options: .curveLinear, animations: {() -> Void in
                                    self.imageView.transform = self.imageView.transform.rotated(by: .pi / 2)
                                }, completion: {(_ finished: Bool) -> Void in
                                    if finished {
                                        rotateImageView()
                                    }
                                })
                            }
                            

                            【讨论】:

                              【解决方案26】:

                              David Rysanek 的绝妙答案已更新至 Swift 4

                              import UIKit
                              
                              extension UIView {
                              
                                      func startRotating(duration: CFTimeInterval = 3, repeatCount: Float = Float.infinity, clockwise: Bool = true) {
                              
                                          if self.layer.animation(forKey: "transform.rotation.z") != nil {
                                              return
                                          }
                              
                                          let animation = CABasicAnimation(keyPath: "transform.rotation.z")
                                          let direction = clockwise ? 1.0 : -1.0
                                          animation.toValue = NSNumber(value: .pi * 2 * direction)
                                          animation.duration = duration
                                          animation.isCumulative = true
                                          animation.repeatCount = repeatCount
                                          self.layer.add(animation, forKey:"transform.rotation.z")
                                      }
                              
                                      func stopRotating() {
                              
                                          self.layer.removeAnimation(forKey: "transform.rotation.z")
                              
                                      }   
                              
                                  }
                              }
                              

                              【讨论】:

                              • 对我来说效果很好(在 UIButton 上)。谢谢!
                              • 我喜欢你的简单
                              【解决方案27】:

                              使用关键帧动画的 Swift 5 UIView 扩展

                              这种方式让我们可以直接使用 UIView.AnimationOptions.repeat

                              public extension UIView {
                              
                                  func animateRotation(duration: TimeInterval, repeat: Bool, completion: ((Bool) -> ())?) {
                              
                                      var options = UIView.KeyframeAnimationOptions(rawValue: UIView.AnimationOptions.curveLinear.rawValue)
                              
                                      if `repeat` {
                                          options.insert(.repeat)
                                      }
                              
                                      UIView.animateKeyframes(withDuration: duration, delay: 0, options: options, animations: {
                              
                                          UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25, animations: {
                                              self.transform = CGAffineTransform(rotationAngle: CGFloat.pi/2)
                                          })
                              
                                          UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25, animations: {
                                              self.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
                                          })
                              
                                          UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25, animations: {
                                              self.transform = CGAffineTransform(rotationAngle: 3*CGFloat.pi/2)
                                          })
                              
                                          UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25, animations: {
                                              self.transform = CGAffineTransform(rotationAngle: 2*CGFloat.pi)
                                          })
                              
                                      }, completion: completion)
                              
                                  }
                              
                              }
                              

                              【讨论】:

                              • 我喜欢你的,也很干净
                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2011-03-26
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-10-19
                              • 2022-01-05
                              相关资源
                              最近更新 更多