UIView Infinite 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、再度開始する前に度。

回答:


334

私にとって完璧に機能するメソッドを見つけました(少し変更しました):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"];
}

25
#import <QuartzCore / QuartzCore.h>
AlBeebe

3
QuartzCore.framework Project-> Build Phases-> Link Binariesを追加
gjpc

9
これはiOS 3.0以下に適したコードですが、新しいプログラマや新しいプロジェクトでは、ドキュメント内のこれらのメソッドからユーザーに警告するようになりました。@ Nateコードは、現在Appleが好むブロックベースのアニメーションを使用しています
PaulWoodIII

1
@cvsguimaraesドキュメントから:「プロパティの値が前の繰り返しサイクルの最後の値に現在の繰り返しサイクルの値を足したものかどうかを判断します。」
smad 2013年

12
これは、[view.layer removeAllAnimations]の助けになるかもしれません 必要に応じてアニメーションを停止します。
arunit21 14

112

このアイデアはリチャードJ.ロス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メソッドは、完璧に滑らかなアニメーションを生成します。
Arjun Mehta 2014

1
@Dilip、交換してくださいM_PI / 2- (M_PI / 2)。(各行の終わりを確認するには、コードを右にスクロールします)
2014

1
@Dilip、コードで使用している期間がわかりません。0.5私と同じように、90度あたりの秒数は同じですか?もしそうなら、私のコードはあなたが90度回転のほんの一部で停止することを許可しません。90度間隔の整数で停止することができますが、「eased out」という90度の回転が1つ追加されます。したがって、上記のコードでは、stopSpin0.35秒後に呼び出した場合、さらに0.65秒間スピンし、180度の合計回転で停止します。より詳細な質問がある場合は、おそらく新しい質問を開く必要があります。この回答に自由にリンクしてください。
2014年

1
@MohitJethwa、何が起こっていると思いますか?これを使用するアプリがありますが、iOS 8.1でも動作します。
2014

1
@Hemang、確かに、それはこの質問がそうだったものではありません。これがあなたがやろうとしていることなら、私は新しい質問を投稿します。
2017

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とは何ですか?
ルダ、2015

これは一定の文字列キーであり、アニメーションの識別と検索に役立ちます。任意の文字列を指定できます。削除プロセスでは、アニメーションが検索され、このキーによって削除されたことがわかります。
カーディ2015

文字列か何か特定のものですか?
Luda、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];
        }
    }];
}

「CGAffineTransformMakeRotation」の代わりに「CGAffineTransformRotate」を使用しました。前者はアニメーションの進行に応じて保存された結果を返すためです。これにより、アニメーション中のビューのジャンプやリセットが防止されます。

もう1つは、「UIViewAnimationOptionRepeat」を使用しないことです。アニメーションが終了する前に、アニメーションが繰り返され始めると、変換がリセットされ、ビューが元の位置に戻ります。繰り返しではなく、再帰して、アニメーションブロックが実質的に終了しないため、変換が元の値にリセットされないようにします。

そして最後に、360または180度(2 * M_PIまたはM_PI)ではなく90度(M_PI / 2)のステップでビューを変換する必要があります。なぜなら、変換は正弦値と余弦値の行列乗算として発生するからです。

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

したがって、180度の変換を使用する場合、180のコサインにより-1が得られ、ビューは毎回反対方向に変換されます(変換のラジアン値をM_PIに変更すると、Note-Nateの回答にもこの問題があります)。360度の変換は、ビューを元の場所に残すように要求するだけなので、回転はまったく表示されません。


私の答え(およびリチャードの答え)の重要な点は、方向の切り替えを回避するために90度のステップを使用することです。多くの画像には180度または90度の対称性があるため、回転を停止したい場合でも90度は比較的うまく機能します
2013

はい、なぜそれが使用されているのか説明しようと思いました:)
ram

2
@nikしかし、そこにブレークポイントを設定した後、完了ブロックがシステムによって呼び出されるため、スタックオーバーフローは発生しないことがわかりますrotateImageView。その意味では、それは本当に再帰的ではありません。
ハギー、2013

1
望ましい機能を備えたコードの小さなバージョンの良い答え+1。
Pradeep Mittal、

1
UIViewAnimationOptionRepeatを使用しない理由の説明に本当に感謝しています。
Jonathan Zhan、2014年

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

私の経験では、これは問題なく動作しますが、画像がオフセットなしでその中心を中心に回転できることを確認してください。

スピンの方向を変えるには、 angleangle *= -1)のます。

更新 @AlexPretzlavのコメントは私がこれを再訪作られた、と私は私がこれを書いたとき、それはかかわらず、私が回転した画像は、画像が実際にのみ90度回転して、リセットした意味、垂直および水平軸の両方に沿って反映されたことに気づい見えたようにずっと回転し続けていました。

したがって、画像が私のようである場合、これはうまく機能しますが、画像が対称的でない場合、「スナップ」が90度後に元の方向に戻ることに気付くでしょう。

非対称の画像を回転させるには、受け入れられた答えを使用するほうがよいでしょう。

以下に示すこれらのエレガントではないソリューションの1つは、本当に画像を回転させますが、アニメーションを再開すると、目立った途切れが生じる可能性があります。

- (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 14年

@AlexPretzlav必ずUIViewAnimationOptionRepeatアニメーションに設定してくださいoptions
levigroker 2014年

1
私はそうしました、それは45°回転し、次に0°に戻り、再び45°回転することによってループします
Alex Pretzlav

なぜこれが「機能した」のかについての新しい情報で私の回答を更新しました
levigroker '17 / 11/14

21

チェックされたソリューションからのSwift拡張機能による私の貢献:

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

非推奨:

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

Swift 4に更新されたDavid Rysanekの素晴らしい答え:

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上で)。ありがとうございました!
agrippa

私はあなたのシンプルさが好きだった
ニコラス

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);への私の質問では、あなたが使用しましたが、アニメーションにはまだわずかな遅延があり、次のターンの前にリセットされます
Derek

10

これは私のために働いていました:

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

それは無限の時間には起こりません!
byJeevan

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、数学はプログラミングのようなもので、複数の方法で同じことを行うことができます。これは、1つの方法のみが正しいことを意味し、他の方法は正しくないことを意味しません。はい、すべての方法についていくつかの長所と短所がある可能性がありますが、それはあなたが誰かのプログラミング方法について質問できるという意味ではありません。あなたはこの方法の短所とあなたの方法の長所を提案できます。このコメントは不快なものなので、このようなコメントは追加しないでください。
Dilip

1
ディリップの気分を害して申し訳ありませんが、2 * M_PIを書くことは((360 * M_PI)/ 180)よりも客観的に明確であり、後者を書くことは目前の主題の理解の欠如を示しています。
BreadicalMD、2015年

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

またstartRotate、ではviewWillAppearなく電話をかけることを忘れないでください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秒ですか?
アレシル2013年

3

誰かがナテスの解決策を望んでいるが迅速にしたい場合は、大まかな迅速な翻訳があります:

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 2016

1
旗を立ててみませんか?だから、多分あなたはアニメーションを停止するためのfuncを持っているでしょう: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()
}

このアニメーションを停止するには、単にに設定nilendlessRotaterます。

興味がある場合は、ご覧ください:https : //github.com/hip4yes/Animatics


1

スウィフト4

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

参照


1

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

1

キーフレームアニメーションを使用したSwift 5 UIView Extension

このアプローチにより、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)

    }

}

2
私もあなたのものが好きです、とてもきれいです
ニコラ・マンジニ

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 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.