UIView Infinite 360 degree rotation animation?

2019-01-01 07:44发布

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.

26条回答
只靠听说
2楼-- · 2019-01-01 08:30

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")
查看更多
长期被迫恋爱
3楼-- · 2019-01-01 08:30

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;
    }
    
查看更多
回忆,回不去的记忆
4楼-- · 2019-01-01 08:32

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();
查看更多
与君花间醉酒
5楼-- · 2019-01-01 08:34

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

        }   

    }
}
查看更多
冷夜・残月
6楼-- · 2019-01-01 08:34

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


    }
查看更多
看淡一切
7楼-- · 2019-01-01 08:35

Found a method (I modified it a bit) that worked perfectly for me: 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"];
}
查看更多
登录 后发表回答