首页 文章

UIView无限360度旋转动画?

提问于
浏览
222

我正在尝试旋转 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度),它可以工作,但如果我再次调用该方法,它会向后旋转 .

EDIT

[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 度,暂停一瞬间,然后重新开始重新调整到_420775度 .

26 回答

  • 2

    创建动画

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

    这个答案有何不同?如果大多数函数返回对象而不是仅仅操作某些对象,那么您将获得更清晰的代码 .

  • 321

    斯威夫特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")
    
  • 0

    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,注意 - Nate的答案也会有这个问题) . 360度转换只是要求视图保持原样,因此您根本看不到任何旋转 .

  • 9

    我从已检查的解决方案中对Swift Extension的贡献:

    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")
        }
    }
    

    Deprecated :

    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")
        }
    }
    
  • 2

    使用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 
    }
    
  • 3

    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()
            }
        })
    }
    
  • 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");
    }
    
  • 0

    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")
    
            }   
    
        }
    }
    
  • 2

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

    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()
                }
        }
    }
    
  • 1

    这对我有用:

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

    一个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 .

  • 9

    如果您想要做的就是无休止地旋转图像,这非常有效,并且非常简单:

    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就会“跳跃” .

    要更改旋转方向,请更改 angleangle *= -1 )的符号 .

    Update @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

    使用四分之一转,并逐步增加转弯 .

    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);
    
  • 21

    Swift :

    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")
    
    
        }
    
  • 10

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

    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()
        }
    }
    
  • 3

    这就是我如何向正确方向旋转360度 .

    [UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionRepeat|UIViewAnimationOptionCurveLinear
                         animations:^{
                             [imageIndView setTransform:CGAffineTransformRotate([imageIndView transform], M_PI-0.00001f)];
                         } completion:nil];
    
  • 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"];
    }
    
  • 9

    Swift 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

  • 9

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

    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

  • 1

    我认为你应该更好地添加 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;
    }
    
  • 1

    这是我作为UIView扩展的快速解决方案 . 它可以被视为在任何UIImageView上模拟UIActivityIndicator行为 .

    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")
        }
    
    }
    
  • 3

    在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)
        }
    }
    
  • 0

    我在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
    
  • 106
    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)
    })
    
  • 4

    感谢Richard J. Ross III的想法,但我发现他的代码并不是我所需要的 . 我相信 options 的默认值是给你 UIViewAnimationOptionCurveEaseInOut ,这在连续动画中看起来不对 . 此外,我添加了一个检查,以便我可以在需要时(或者 infinite ,但是 indefinite 持续时间)在偶数四分之一圈停止我的动画,并使加速度在前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 .

  • 64

    您也可以使用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();
        }
    }
    

相关问题