UIView 360度无限旋转动画?


251

我正在尝试旋转UIImageView360度,并在线查看了一些教程。如果没有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度数,然后再次开始。

Answers:


334

找到了一个对我最合适的方法(我做了一点修改):iphone UIImageView旋转

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

25
#import <QuartzCore / QuartzCore.h>
AlBeebe 2012年

3
添加QuartzCore.framework项目->构建阶段->链接二进制文件
gjpc 2012年

9
这是适用于iOS 3.0及以下版本的正确代码,但对于较新的程序员和新项目,Apple现在警告用户不要使用Docs&@Nate代码中的这些方法,而是使用Apple现在更喜欢的基于块的动画
PaulWoodIII 2013年

1
@cvsguimaraes来自文档:“确定属性值是否为上一个重复周期结束时的值加上当前重复周期的值。”
smad

12
这可能会帮助一些人, [view.layer removeAllAnimations]; 在需要时停止动画。
arunit21

112

理查德·J·罗斯三世(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),而上一个旋转结束(完成)时。Github上的示例项目。


2
使用此方法,我注意到每个PI / 2角度(90度)中的动画都有短暂的暂停,并且使用CABasicAnimation所选择的答案比CPU使用率略有增加。CABasicAnimation方法可产生完美流畅的动画。
2014年

1
@Dilip,替换M_PI / 2- (M_PI / 2)。(向右滚动代码以查看每行的结尾)
Nate

1
@Dilip,我不知道您在代码中使用的持续时间。0.5和我一样,每90度的秒数相同吗?如果是这样,我的代码不会让你停在分数 90度旋转。它允许您以90度的整数间隔停止,但又增加了一个90度的旋转角度,“逐渐减小”。因此,在上面的代码中,如果stopSpin在0.35秒后调用,它将再旋转0.65秒,并在180度旋转时停止。如果您有更详细的问题,则可能应该打开一个新问题。随意链接到这个答案。
内特2014年

1
您看到了什么,@ MohitJethwa?我有一个使用此功能的应用程序,它仍然适用于iOS 8.1。
Nate

1
@Hemang,当然,但这不是这个问题。如果这是您要尝试的操作,我会发布一个新问题。
Nate

85

在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?
卢达

这是一个恒定的String键,可以帮助您识别和搜索动画。它可以是您想要的任何字符串。在删除过程中,您可以看到动画已被此键搜索并删除。
卡迪2015年

它是任何字符串还是特定的东西?
卢达,2015年

对不起,我晚回答了,但是可以,它可以是任何字符串。
卡迪2015年

1
//答案中的所有键
Zander Zhang

67

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度对称性。
Nate

是的,我只是想解释一下为什么要使用它:)
ram

2
@nik但是在其中设置断点后,我看到不会有堆栈溢出,因为完成块是由系统调用的,到那时为止rotateImageView已经完成了。因此,从这个意义上说,它并不是真正的递归。
huggie 2013年

1
对于具有所需功能的小版本代码,良好的答案+1。
Pradeep Mittal

1
我真的很感谢为什么不使用UIViewAnimationOptionRepeat的解释。
詹纳森·詹

21

如果您要做的就是无限旋转图像,则效果很好,并且非常简单:

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)的符号。

@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
对我来说,这只旋转了1/4圈。
Alex Pretzlav 2014年

@AlexPretzlav确保已UIViewAnimationOptionRepeat设置动画options
levigroker 2014年

1
我做到了,它旋转45°,然后跳回到循环至0℃,再旋转45°
亚历Pretzlav

更新了我的回答,并提供了有关为何执行此操作的新信息
levigroker

21

我对选中的解决方案中的Swift Extension的贡献:

迅捷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
罗杰斯先生

15

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上)。谢谢!
阿格里帕

我喜欢您的简单性
Nicolas Manzini

10

使用四分之一圈,并逐渐增加圈数。

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(^)(BOOL)”类型的参数发送“ void(^ const__strong()”的不兼容块指针类型。我试图在代码中更改旋转方法在我的问题给imageToMove.transform = CGAffineTransformRotate(imageToMove.transform,M_PI / 2);你使用,动画还是有轻微的延迟,以及前翻下复位。
德里克-

10

这为我工作:

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

它没有无限次发生!
byJeevan '16

9

我在该存储库中找到了不错的代码,

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

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

1
很抱歉,它使您恼怒了Dilip,但是客观地写2 * M_PI比((360 * M_PI)/ 180)更清楚,而编写后者表明您对当前的主题缺乏理解。
BreadicalMD

1
@BreadicalMD不用担心,但是它的好建议,我已经更新了我的代码。谢谢
Dilip

9

这是我作为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")
    }

}

9

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

请记住调用startRotateviewWillAppear没有viewDidLoad


3

您也可以使用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/30秒,这样我就可以实时修改对象的旋转速度,例如对触摸做出反应?
alecail 2013年

3

如果有人想迅速解决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

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

2

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

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

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

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


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 
}

2

@ram的回答确实很有帮助。这是答案的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()
        }
    }
}

如何停止旋转?
user2526811 '16

1
那你放个旗呢?因此,也许您有一个用于停止动画的功能:var stop = false private func stopRotation() { stop = true } 然后,在里面if finished {...}if finished { if stop { return} self.rotateImageView() }
yoninja

谢谢,我完全一样。感谢您的答复。
user2526811

1

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

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

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

1

使用关键帧动画的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)

    }

}

1
我也喜欢您的,也很干净
Nicolas Manzini

0

斯威夫特:

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


    }

0

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

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

做得好。我只想评论UIImageView类别。谢谢你们
Zgpeace
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.