I need to rotate a UIView
indefinitely. However, I need to be able to stop it per a method, as I'm trying to implement something like a custom UIActivityIndicatorView
. The view also needs to animate back to its starting rotation (0 degrees). The problem with all the approaches I've been trying to implement so far is that I'm either unable to stop it manually (until the duration ends), the animation isn't smooth or my view doesn't return back to its starting position.
Basically, what I need is an animation to rotate my view forever. Once I call a method to stop it, it should return to its starting point and stop.
I've tried a few modified answers here, but no success.
OK, just built this to check if it would work.
In Swift (because I'm learning) I've done this...
import UIKit
class ViewController: UIViewController {
@IBOutlet var rotatingView : UIView
var rotating = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func start(sender : AnyObject) {
rotating = true
rotateOnce()
}
func rotateOnce() {
UIView.animateWithDuration(1.0,
delay: 0.0,
options: .CurveLinear,
animations: {self.rotatingView.transform = CGAffineTransformRotate(self.rotatingView.transform, 3.1415926)},
completion: {finished in self.rotateAgain()})
}
func rotateAgain() {
UIView.animateWithDuration(1.0,
delay: 0.0,
options: .CurveLinear,
animations: {self.rotatingView.transform = CGAffineTransformRotate(self.rotatingView.transform, 3.1415926)},
completion: {finished in if self.rotating { self.rotateOnce() }})
}
@IBAction func stop(sender : AnyObject) {
rotating = false
}
}
Essentially, each single rotation is one animation. Then in the completion block I inspect a boolean rotating
. If rotating == true
then I run the rotation again. and again. and again.
When rotating == false
then I just don't run the animation again from the completion block.
This ensures that the last animation gets to its end before actually stopping the animation.
Objective-C version
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *rotatingView;
@property (nonatomic, assign) BOOL rotating;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startRotating:(id)sender {
self.rotating = YES;
[self firstRotation];
}
- (IBAction)stopRotating:(id)sender {
self.rotating = NO;
}
- (void)firstRotation
{
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.rotatingView.transform = CGAffineTransformRotate(self.rotatingView.transform, M_PI);
}
completion:^(BOOL finished) {
[self secondRotation];
}];
}
- (void)secondRotation
{
[UIView animateWithDuration:1.0
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
self.rotatingView.transform = CGAffineTransformRotate(self.rotatingView.transform, M_PI);
}
completion:^(BOOL finished) {
if (self.rotating) {
[self firstRotation];
}
}];
}
@end
Add this code where ever you want to perform your animation
In Objective-C
-(BOOL)rotateAnimation:(BOOL)check
{
if (check)
{
[UIView animateWithDuration:0.5f animations:^{
[ANIMATING_VIEW_OUTLET setAlpha:0.0f];
}completion:^(BOOL finished){
[ANIMATING_VIEW_OUTLET.layer removeAllAnimations];
[self.view sendSubviewToBack:ANIMATING_VIEW_OUTLET];
}];
return NO;
}
else
{
[self.view bringSubviewToFront:ANIMATING_VIEW_OUTLET];
[UIView animateWithDuration:0.5f animations:^{
[ANIMATING_VIEW_OUTLET setAlpha:1.0f];
}];
CABasicAnimation* animationFull = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animationFull.fromValue = @0.0f;
animationFull.toValue = @(2*M_PI);
animationFull.duration = 0.75f; // this might be too fast
animationFull.repeatCount = HUGE_VALF; // HUGE_VALF is defined in math.h so import it
[ANIMATING_VIEW_OUTLET.layer addAnimation:animationFull forKey:@"rotation"];
return YES;
}
}
To invoke/start animation
[self rotateAnimation:YES];
To stop animation
[self rotateAnimation:YES];
In Swift 2.2
func rotateAnimation(check : Bool) -> Bool {
if check == true {
UIView.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
kAnimatingViewOutlet.alpha = 0
}, completion: { (finished) in
kAnimatingViewOutlet.layer.removeAllAnimations()
})
return false
}
else if check == false {
UIView.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
kAnimatingViewOutlet.alpha = 1
}, completion: { (finished) in
})
let animationFull : CABasicAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
animationFull.fromValue = 0
animationFull.toValue = 2*M_PI
animationFull.duration = 0.75 // this might be too fast
animationFull.repeatCount = Float.infinity
kAnimatingViewOutlet.layer.addAnimation(animationFull, forKey: "rotation")
return true
else {
print("check value is nil")
}
}
To invoke/start animation
rotateAnimation(true)
To stop animation
rotateAnimation(false)