UIView无限360度旋转动画?

我正在尝试旋转一个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,它根本不会移动(因为它是相同的位置)。如果我尝试只做(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度。

171317 次浏览

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

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

找到了一个方法(我稍微修改了一下),它非常适合我: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"];
}

感谢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上

你也可以用UIView和block做同样类型的动画。下面是一个类扩展方法,它可以以任何角度旋转视图。

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

如果你想要做的只是无休止地旋转图像,这很好,而且非常简单:

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。

要改变自旋的方向,改变angle (angle *= -1)的符号。

@AlexPretzlav的评论让我重新审视这一点,我意识到,当我写这张我旋转的图像是沿着垂直和水平轴的镜像,这意味着图像确实只旋转了90度,然后重置,尽管它看起来像它继续旋转所有的方式。

所以,如果你的图像像我的一样,这将工作得很好,然而,如果图像不是对称的,你会注意到90度后“snap”回到原来的方向。

要旋转非对称图像,最好使用公认的答案。

这些不太优雅的解决方案之一,如下所示,将真正旋转图像,但当动画重新启动时可能会有明显的口吃:

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

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度变换,cos(180)产生-1,使得视图每次都在相反的方向变换(如果你把变换的弧度值改为M_PI, Note-Nate的答案也会有这个问题)。360度转换只是要求视图保持在原来的位置,因此你根本看不到任何旋转。

我在这个存储库中找到了很好的代码,

下面是它的代码,我做了一些小的改变,根据我的速度需要:)

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

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

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

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

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

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

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

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

我的贡献与一个快速扩展从检查解决方案:

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

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

迅速:

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




}

这对我很管用:

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

这是我的快速解决方案作为一个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")
}


}

创建动画

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

这个答案有什么不同?如果你的大部分函数都返回对象,而不是在这里和那里操作一些对象,你会有更干净的代码。

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

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

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中调用。

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

使用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")
< p > < br > 这是UIView的一个扩展函数,它处理start &停止旋转操作:

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")
}
}
< p > < br > 现在使用,UIView.animation闭包:

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

我认为你最好添加一个UIVIew Category:

#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)];//加上这个负号,因为我想把它逆时针旋转
    fullRotation。Duration =持续时间;
    fullRotation。速度= 2.0f;//改变转速
    if (repeatCount == 0)
    fullRotation。repeatCount = MAXFLOAT;
    其他的
    fullRotation。repeatCount = repeatCount;
    
    
    (自我。layer addAnimation:fullRotation forKey:@"360"];
    }
    < /代码> < / pre > < /李>
    

不使用此方法:)

    <李> < pre > <代码> remstopAllAnimations (void) { (自我。层removeAllAnimations]; }; < /代码> < / pre > < /李> <李> < pre > <代码> rempauseAnimations (void) { (自我rempauseLayer: self.layer); } < /代码> < / pre > < /李> <李> < pre > <代码> remresumeAnimations (void) { (自我remresumeLayer: self.layer); } < /代码> < / pre > < /李> <李> < pre > <代码> (void) rempauseLayer: (CALayer *)层 { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 层。速度= 0.0; 层。timeOffset = pausedTime; } < /代码> < / pre > < /李> <李> < pre > <代码> (void) remresumeLayer: (CALayer *)层 { CFTimeInterval pausedTime = [layer timeOffset]; 层。速度= 1.0; 层。timeOffset = 0.0; 层。beginTime = 0.0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 层。beginTime = timeSincePause; } < /代码> < / pre > < /李>

斯威夫特4,

func rotateImage(image: UIImageView) {
UIView.animate(withDuration: 1, animations: {
image.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
image.transform = CGAffineTransform.identity
}) { (completed) in
self.rotateImage()
}
}

< a href = " https://stackoverflow.com/a/35707234/3411787 " > Ref < / >

斯威夫特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()
}
})
}

David Rysanek的精彩回答更新到斯威夫特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")


}


}
}

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)


}


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

}
    

}