UIView Infinite 360 degree rotation animation?

IosObjective CAnimationUiviewCore Animation

Ios Problem Overview


I'm trying to rotate a UIImageView 360 degrees, and have looked at several tutorials online. I could get none of them working, without the UIView either stopping, or jumping to a new position.

  • How can I achieve this?

The latest thing I've tried is:

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

But if I use 2*pi, it doesn't move at all (since it's the same position). If I try to do just pi (180 degrees), it works, but if I call the method again, it rotates backwards.

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!");
				 }];

doesn't work either. It goes to 180 degrees, pauses for a split second, then resets back to 0 degrees before it starts again.

Ios Solutions


Solution 1 - Ios

Found a method (I modified it a bit) that worked perfectly for me: https://stackoverflow.com/questions/1421050/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"];
}

Solution 2 - Ios

Kudos to Richard J. Ross III for the idea, but I found that his code wasn't quite what I needed. The default for options, I believe, is to give you UIViewAnimationOptionCurveEaseInOut, which doesn't look right in a continuous animation. Also, I added a check so that I could stop my animation at an even quarter turn if I needed (not infinite, but of indefinite duration), and made the acceleration ramp up during the first 90 degrees, and decelerate during the last 90 degrees (after a stop has been requested):

// 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;
}

##Update

I added the ability to handle requests to start spinning again (startSpin), while the previous spin is winding down (completing). Sample project here on Github.

Solution 3 - Ios

In Swift, you can use the following code for infinite rotation:

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

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

Stopping is like:

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

Solution 4 - Ios

Nate's answer above is ideal for stop and start animation and gives a better control. I was intrigued why yours didn't work and his does. I wanted to share my findings here and a simpler version of the code that would animate a UIView continuously without stalling.

This is the code I used,

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

I used 'CGAffineTransformRotate' instead of 'CGAffineTransformMakeRotation' because the former returns the result which is saved as the animation proceeds. This will prevent the jumping or resetting of the view during the animation.

Another thing is not to use 'UIViewAnimationOptionRepeat' because at the end of the animation before it starts repeating, it resets the transform making the view jump back to its original position. Instead of a repeat, you recurse so that the transform is never reset to the original value because the animation block virtually never ends.

And the last thing is, you have to transform the view in steps of 90 degrees (M_PI / 2) instead of 360 or 180 degrees (2*M_PI or M_PI). Because transformation occurs as a matrix multiplication of sine and cosine values.

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

So, say if you use 180-degree transformation, the cosine of 180 yields -1 making the view transform in opposite direction each time (Note-Nate's answer will also have this issue if you change the radian value of transformation to M_PI). A 360-degree transformation is simply asking the view to remain where it was, hence you don't see any rotation at all.

Solution 5 - Ios

My contribution with a Swift Extension from the checked solution :

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

Solution 6 - Ios

If all you want to do is rotate the image endlessly, this works quite well, and is very simple:

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

In my experience, this works flawlessly, but be sure your image is capable of being rotated around its center without any offsets, or the image animation will "jump" once it makes it around to PI.

To change the direction of the spin, change the sign of angle (angle *= -1).

Update Comments by @AlexPretzlav made me revisit this, and I realized that when I wrote this the image I was rotating was mirrored along both the vertical and horizontal axis, meaning the image was indeed only rotating 90 degrees and then resetting, though it looked like it was continuing to rotate all the way around.

So, if your image is like mine was, this will work great, however, if the image is not symmetrical, you'll notice the "snap" back to the original orientation after 90 degrees.

To rotate a non-symmetrical image, you're better off with the accepted answer.

One of these less elegant solutions, seen below, will truly rotate the image, but there may be a noticeable stutter when the animation is restarted:

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

You could also do this just with blocks, as @richard-j-ross-iii suggests, but you will get a retain loop warning since the block is capturing itself:

__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();

Solution 7 - Ios

David Rysanek's awesome answer updated to 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")
    
        }   

    }
}

Solution 8 - Ios

This was working for me:

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

Solution 9 - Ios

Here is my swift solution as a UIView extension. It could be considered as a simulation of a UIActivityIndicator behaviour on any UIImageView.

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

}

Solution 10 - Ios

Use quarter turn, and increase the turn incrementally.

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

Solution 11 - Ios

I have found nice code in this repository,

Here is the code from it i have done small changes according to my need for speed :)

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

Solution 12 - Ios

A Swift3 version:

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

And remember to call startRotate in viewWillAppear not in viewDidLoad.

Solution 13 - Ios

@ram's answer was really helpful. Here's a Swift version of the 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()
            }
    }
}

Swift 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()
        }
    }
}

Solution 14 - Ios

You can also do the same type of animation using UIView and blocks. Here is a class extension method which can rotate the view by any angle.

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

Solution 15 - Ios

If anyone wanted nates' solution but in swift, then here is a rough swift translation:

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

Solution 16 - Ios

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

Solution 17 - Ios

This is how I rotate 360 in right direction.

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

Solution 18 - Ios

Create the animation

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

Add it to a view like this

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

How is this answer different? You will have way cleaner code if most of your functions returns objects instead of just manipulating some objects here and there.

Solution 19 - Ios

There are following different ways to perform 360 degree animation with UIView.

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


Here is an extension functions for UIView that handles start & stop rotation operations:

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


Now using, UIView.animation closure:

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

Solution 20 - Ios

Swift 5 UIView Extension using Keyframe Animations

This approach allows us to directly use the 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)
        
    }
    
}

Solution 21 - Ios

I has developed a shiny animation framework which can save you tone of time! Using it this animation can be created very easily:

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

to stop this animation simply set nil to endlessRotater.

If you are interested, please take a look: https://github.com/hip4yes/Animatics

Solution 22 - Ios

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

Solution 23 - Ios

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

Solution 24 - Ios

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

Solution 25 - Ios

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

Solution 26 - Ios

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

Solution 27 - Ios

import UIKit

class RotatingImageView: UIImageView, CAAnimationDelegate {
    
    private let rotationAnimationKey = "rotationAnimationKey"

    private var shouldStopRotating = false
    
    func startRotating(witFullRotationDuration duration: Double = 0.5, halfRotation: Bool = true) {
        
        shouldStopRotating = false
        if layer.animation(forKey: rotationAnimationKey) == nil {
        
            let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
            rotationAnimation.fromValue = 0.0
            rotationAnimation.toValue = halfRotation ? Float.pi : Float.pi * 2
            rotationAnimation.duration = duration
            rotationAnimation.repeatCount = 1
            rotationAnimation.delegate = self
            layer.add(rotationAnimation, forKey: rotationAnimationKey)
        
        }
        
    }

    func stopRotating(immediately: Bool = false) {
        if immediately {
            if layer.animation(forKey: rotationAnimationKey) != nil {
                layer.removeAnimation(forKey: rotationAnimationKey)
            }
        } else {
            shouldStopRotating = true
        }
    }
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    
        if !shouldStopRotating {
            startRotating(witFullRotationDuration: anim.duration)
        } else {
            if layer.animation(forKey: rotationAnimationKey) != nil {
                layer.removeAnimation(forKey: rotationAnimationKey)
            }
        }
        
    }
    
}

Solution 28 - Ios

I think you should better add a UIVIew Category:

#import <QuartzCore/QuartzCore.h>
#import "UIView+Rotate.h"
Implementation UIView (Rotate)
  •   (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"];
      }
    
Not using this methods :)
  •   (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;
      }
    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDerekView Question on Stackoverflow
Solution 1 - IosDerekView Answer on Stackoverflow
Solution 2 - IosNateView Answer on Stackoverflow
Solution 3 - IosKádiView Answer on Stackoverflow
Solution 4 - IosramView Answer on Stackoverflow
Solution 5 - IosKevin ABRIOUXView Answer on Stackoverflow
Solution 6 - IoslevigrokerView Answer on Stackoverflow
Solution 7 - IosGeoff HView Answer on Stackoverflow
Solution 8 - Iosinigo333View Answer on Stackoverflow
Solution 9 - IosDavid RysanekView Answer on Stackoverflow
Solution 10 - IosRichard J. Ross IIIView Answer on Stackoverflow
Solution 11 - IosDilipView Answer on Stackoverflow
Solution 12 - IosVictor ChoyView Answer on Stackoverflow
Solution 13 - IosyoninjaView Answer on Stackoverflow
Solution 14 - IosMiKLView Answer on Stackoverflow
Solution 15 - IosAdrian_HView Answer on Stackoverflow
Solution 16 - IosDanil ShaykhutdinovView Answer on Stackoverflow
Solution 17 - IosPavelView Answer on Stackoverflow
Solution 18 - IoshfossliView Answer on Stackoverflow
Solution 19 - IosKrunalView Answer on Stackoverflow
Solution 20 - IosBrody RobertsonView Answer on Stackoverflow
Solution 21 - IosNikita ArkhipovView Answer on Stackoverflow
Solution 22 - IosMohammad Zaid PathanView Answer on Stackoverflow
Solution 23 - IosAbhishek JainView Answer on Stackoverflow
Solution 24 - IosErhan DemirciView Answer on Stackoverflow
Solution 25 - IosDeepak CarpenterView Answer on Stackoverflow
Solution 26 - IosWarif Akhand RishiView Answer on Stackoverflow
Solution 27 - IosPeter LapisuView Answer on Stackoverflow
Solution 28 - IosZgpeaceView Answer on Stackoverflow