UIView Sonsuz 360 derece döndürme animasyonu?


251

UIImageView360 derece döndürmeye çalışıyorum ve çevrimiçi birkaç öğreticiye baktım. Hiçbirini UIViewdurmadan ya da yeni bir pozisyona atlamaksızın çalıştıramadım.

  • Bunu nasıl başarabilirim?

Denediğim son şey:

[UIView animateWithDuration:1.0
                      delay:0.0
                    options:0
                 animations:^{
                     imageToMove.transform = CGAffineTransformMakeRotation(M_PI);
                 } 
                 completion:^(BOOL finished){
                     NSLog(@"Done!");
                 }];

Ama 2 * pi kullanırsam, hiç hareket etmez (aynı pozisyonda olduğu için). Sadece pi (180 derece) yapmaya çalışırsam çalışır, ancak yöntemi tekrar çağırırsam geriye doğru döner.

DÜZENLE :

[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!");
                 }];

çalışmıyor. Derecelere gider 180, bir saniyeliğine duraklar, sonra 0tekrar başlamadan önce derecelere geri döner .

Yanıtlar:


334

Benim için mükemmel çalışan bir yöntem buldum (biraz değiştirdim): iphone UIImageView döndürme

#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
add QuartzCore.framework Projesi-> Yapı Aşamaları-> Bağlantı İkili
Kodları

9
Bu, iOS 3.0 ve altı için doğru koddur, ancak daha yeni programcılar ve yeni projeler için Apple, şimdi Docs & @Nate kodunda bu yöntemlerden kullanıcıları uyarıyor ve Apple'ın tercih ettiği blok tabanlı animasyonları kullanıyor
PaulWoodIII

1
@cvsguimaraes Dokümandan: "Özelliğin değerinin, önceki yineleme döngüsünün sonundaki değer artı geçerli yineleme döngüsünün değeri olup olmadığını belirler."
smad

13
Bu bazılarına yardımcı olabilir, [view.layer removeAllAnimations]; gerektiğinde animasyonu durdurmak için.
arunit21

112

Fikir için Richard J. Ross III'e Kudos, ama kodunun tam olarak ihtiyacım olan şey olmadığını buldum. Varsayılan olarak options, sanırım, UIViewAnimationOptionCurveEaseInOutsürekli bir animasyonda doğru görünmeyen size vermektir . Ayrıca, gerektiğinde ( sonsuz değil, belirsiz bir süre) animasyonumu eşit bir çeyrek turda durdurabilmem için bir kontrol ekledim ve ilk 90 derece boyunca hızlanma hızını artırdım ve son 90 derece boyunca yavaşlayabildim (bir durak istendikten sonra):

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

Güncelleme

startSpinÖnceki sıkma azalırken (tamamlanırken), tekrar dönmeye başlama isteklerini ( ) işleme ekledim . Github'da örnek proje .


2
Bunu kullanarak, her PI / 2 açısında (90 derece) animasyonda kısa bir duraklama ve CABasicAnimation kullanarak seçilen cevapta CPU kullanımında marjinal bir artış görüyorum. CABasicAnimation yöntemi kusursuz pürüzsüzlükte bir animasyon üretir.
Arjun Mehta

1
@Dilip, yerini M_PI / 2ile - (M_PI / 2). (Her satırın sonunu görmek için kodu sağa kaydırın)
Nate

1
@Dilip, kodunuzda ne kadar süre kullandığınızı bilmiyorum. 0.590 derece başına aynı saniye, benim gibi mi? Eğer öyleyse, benim kod bir durdurmak izin vermez fraksiyonun 90 derece dönme. 90 derece aralıklarla durmanıza izin verir, ancak ekstra bir 90 derece dönüş ekler, "hafifletir". Yani, yukarıdaki kodda, stopSpin0.35 saniye sonra ararsanız , 0.65 saniye daha dönecek ve toplam 180 derece dönüşte duracaktır. Daha ayrıntılı sorularınız varsa, muhtemelen yeni bir soru açmalısınız. Bu cevapla bağlantı kurmaktan çekinmeyin.
Nate

1
Ne olduğunu görüyorsun, @MohitJethwa? Bunu kullanan bir uygulamam var ve iOS 8.1'de hala çalışıyor.
Nate

1
@Hemang, tabii, ama bu soru böyle değildi. Yapmaya çalıştığın şey buysa yeni bir soru gönderirim.
Nate

85

Swift'te sonsuz dönüş için aşağıdaki kodu kullanabilirsiniz:

Hızlı 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)
        }
    }
}

Hızlı 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)
    }
}

Durdurmak şöyle:

func stopRotatingView(view: UIView) {
    if view.layer.animationForKey(kRotationAnimationKey) != nil {
        view.layer.removeAnimationForKey(kRotationAnimationKey)
    }
}

KRotationAnimationKey nedir?
Luda

Animasyonu tanımanıza ve aramanıza yardımcı olan sabit bir String anahtarıdır. İstediğiniz herhangi bir Dize olabilir. Kaldırma işleminde, animasyonun bu tuşla arandığını ve silindiğini görebilirsiniz.
Kádi

Herhangi bir dize mi yoksa belirli bir şey mi?
Luda

Geç cevap verdiğim için üzgünüm, ama evet, herhangi bir dize olabilir.
Kádi

1
//
Yanıttaki

67

Nate'in yukarıdaki cevabı, animasyonu durdur ve başlat için idealdir ve daha iyi bir kontrol sağlar. Seninkinin neden işe yaramadığını ve onun işe yaradığını merak ettim. Bulgularımı burada ve durmadan kesintisiz bir UIView canlandıracak kodun daha basit bir versiyonunu paylaşmak istedim.

Kullandığım kod bu,

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

Animasyon ilerledikçe kaydedilen sonucu döndürdüğünden, 'CGAffineTransformMakeRotation' yerine 'CGAffineTransformRotate' kullandım. Bu, animasyon sırasında görünümün atlanmasını veya sıfırlanmasını önleyecektir.

Başka bir şey 'UIViewAnimationOptionRepeat' kullanmak değildir, çünkü animasyonun tekrarlanmaya başlamasından önce, görünümü orijinal konumuna geri döndürerek dönüşümü sıfırlar. Tekrarlama yerine, animasyon bloğu neredeyse hiç bitmediği için dönüşümün asla orijinal değerine sıfırlanmaması için tekrarlanırsınız.

Ve son olarak, görünümü 360 veya 180 derece (2 * M_PI veya M_PI) yerine 90 derecelik adımlarla (M_PI / 2) dönüştürmeniz gerekir. Çünkü dönüşüm sinüs ve kosinüs değerlerinin matris çarpımı olarak gerçekleşir.

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

Yani, 180 derecelik dönüşüm kullanırsanız, 180 kosinüsü -1 verir ve her seferinde görünüm dönüşümünü zıt yönde dönüştürür (Dönüşümün radyan değerini M_PI olarak değiştirirseniz Not-Nate'in yanıtı da bu soruna sahip olacaktır). 360 derecelik bir dönüşüm, görünümden olduğu yerde kalmasını istiyor, dolayısıyla hiç rotasyon görmüyorsunuz.


Cevabımın (ve Richard'ın türettiği cevabın) tüm yönü, yön değiştirmekten kaçınmak için 90 derecelik adımlar kullanmaktır . 90 derece de döndürmeyi durdurmak isterseniz nispeten iyi çalışır , çünkü birçok görüntü 180 derece veya 90 derece simetriye sahiptir.
Nate

Evet, neden kullanıldığını açıklayacağımı sanıyordum :)
ram

2
@nik Ancak orada kesme noktası ayarladıktan sonra tamamlama bloğu sistem tarafından çağrıldığı için yığın taşması olmayacağını görüyorum, o zamana rotateImageViewkadar bitmişti. Yani bu anlamda gerçekten tekrarlamalı değil.
huggie

1
İstediğiniz işlevselliğe sahip küçük bir kod sürümü için iyi yanıt +1.
Pradeep Mittal

1
Neden UIViewAnimationOptionRepeat kullanmamanın açıklamasını takdir ettim.
Jonathan Zhan

21

Yapmak istediğiniz tek şey görüntüyü sonsuza kadar döndürmekse, bu oldukça iyi çalışır ve çok basittir:

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

Benim tecrübelerime göre, bu kusursuz çalışıyor, ancak görüntünüzün ofsetleri olmadan merkezi etrafında döndürülebildiğinden emin olun, yoksa görüntü animasyonu PI'ye geçtikten sonra "atlayacaktır".

Sıkma yönünü değiştirmek için angle( angle *= -1) işaretini değiştirin .

Güncelleştirme @AlexPretzlav Notlar beni bu tekrar yaptı ve şunu fark ettim ki ben de, görüntü gerçekten sadece sıfırlamayı sonra 90 derece döndürülmesi ve daha anlam, bu şimdiye dikey ve yatay eksen hem boyunca yansıtılmış edildi dönen edildi görüntü yazdığında baktı gibi her yerde dönmeye devam ediyordu.

Yani, eğer görüntünüz benimki gibi ise, bu çok işe yarayacak, ancak görüntü simetrik değilse, 90 dereceden sonra orijinal yönelime "yapıştığını" göreceksiniz.

Simetrik olmayan bir görüntüyü döndürmek için, kabul edilen cevaptan daha iyi durumdasınız.

Aşağıda görülen bu daha az zarif çözümlerden biri görüntüyü gerçekten döndürür, ancak animasyon yeniden başlatıldığında fark edilebilir bir kekeme olabilir:

- (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'ün önerdiği gibi bunu sadece bloklarla da yapabilirsiniz, ancak blok kendini yakaladığı için bir döngü döngüsü uyarısı alırsınız:

__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
Bu benim için bir rotasyonun sadece 1 / 4'ünü döndürdü.
Alex Pretzlav

@AlexPretzlav UIViewAnimationOptionRepeatAnimasyonunuzda ayarladığınızdan emin olun options.
levigroker

1

Cevabımın neden bu "işe yaradığı" ile ilgili yeni bilgilerle güncellendi
levigroker

21

İşaretli çözümden bir Swift Uzantısı ile katkım:

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

Onaylanmadı:

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

Tekrar sayısı için, biri kullanılabilir .infinity.
Bay Rogers

15

David Rysanek'in harika cevabı Swift 4'e güncellendi :

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

        }   

    }
}

benim için çok iyi çalıştı (bir UIButton üzerinde). Teşekkür ederim!
agrippa

senin sadeliğini beğendim
Nicolas Manzini

10

Çeyrek tur kullanın ve dönüşü kademeli olarak artırın.

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

Ben bloklar için çok yeni ama bu yöntem "void (^ const__strong () '' void (^) (BOOL) 'tür parametresine göndererek uyumsuz blok işaretçi türleri hata atar. Koddaki rotasyon yöntemimi değiştirmeye çalıştım Benim sorum imageToMove.transform = CGAffineTransformRotate (imageToMove.transform, M_PI / 2); kullandınız ve animasyon hala hafif bir gecikmeye sahip ve bir sonraki dönüşten önce sıfırlanıyor
Derek

10

Bu benim için çalışıyordu:

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

Sonsuz zamanlar için değil!
By Evan

9

Bu depoda güzel kod buldum ,

İşte ondan hız hızına göre küçük değişiklikler yaptım :)

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, Matematik programlama gibidir, Aynı şeyi birden çok yolla yapabilirsiniz. Bu sadece 1 yolun doğru, diğer yolun doğru olmadığı anlamına gelmez. Evet, her yol için bazı artıları ve eksileri olabilir, ancak bu, birinin programlama yöntemini sorgulayabileceğiniz anlamına gelmez, bu yöntem için eksilerini ve yönteminiz için eksilerini önerebilirsiniz. Bu yorum gerçekten rahatsız edici ve böyle bir yorum eklememelisiniz.
Dilip

1
Üzgünüm, Dilip'i rahatsız etti, ancak 2 * M_PI yazmak nesnel olarak ((360 * M_PI) / 180) 'den objektif olarak daha net ve ikincisini yazmak, konunun anlaşılmadığını gösteriyor.
BreadicalMD

1
@BreadicalMD Endişelenmeyin, ama iyi bir öneri, kodumu güncelledim. Teşekkürler.
Dilip

9

İşte bir UIView uzantısı olarak hızlı çözümüm. Herhangi bir UIImageView üzerinde bir UIActivityIndicator davranışının bir simülasyonu olarak düşünülebilir.

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

Bir Swift3 sürümü:

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

Ve aramayı unutma startRotateiçinde viewWillAppeardeğil viewDidLoad.


3

UIView ve blokları kullanarak aynı animasyon türünü de yapabilirsiniz. İşte görünümü herhangi bir açıyla döndürebilen bir sınıf genişletme yöntemi.

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

Bu yöntem (tamamlandığında özyinelemeli çağrı) hızlı değişen bir animasyonla iyi çalışır mı? Örneğin, süre yakl. 1 / 30s böylece nesnenin dönüş hızını gerçek zamanlı olarak değiştirebilirim, örneğin dokunuşlara tepki gösterebilir miyim?
alecail

3

Herkes nates çözümünü ancak hızlı bir şekilde istiyorsa, işte kaba bir hızlı çeviri:

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 için:

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'ı bu şekilde doğru yönde döndürüyorum.

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

2

Animasyonu oluşturun

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

Bunun gibi bir görünüme ekleyin

CABasicAnimation *animation = [self spinAnimationWithDuration:1.0 clockwise:YES repeat:YES];
[self.spinningView.layer addAnimation:animation forKey:@"rotationAnimation"];

Bu cevap nasıl farklı? İşlevlerinizin birçoğu sadece burada ve burada bazı nesneleri işlemek yerine nesneleri döndürürse, yol temizleyici kodunuz olacaktır.


2

UIView ile 360 ​​derecelik animasyon gerçekleştirmenin farklı yolları vardır.

CABasicAnimation kullanma

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 için başlatma ve durdurma döndürme işlemlerini işleyen bir uzantı işlevi şunlardır:

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


Şimdi, UIView.animation kapanışını kullanarak :

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

2

@ ram'ın cevabı gerçekten yardımcı oldu. İşte cevabın bir Swift versiyonu.

Hızlı 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()
            }
    }
}

Hızlı 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()
        }
    }
}

rotasyonu nasıl durdurabilirim?
user2526811

1
Bir bayrak koymaya ne dersin? Yani, belki animasyonu durdurmak için bir fonk var: var stop = false private func stopRotation() { stop = true } O zaman, içeride if finished {...}:if finished { if stop { return} self.rotateImageView() }
yoninja

Teşekkürler, ben de aynısını yaptım. Yanıtınız için teşekkürler.
user2526811

1

Size zaman kazandıracak parlak bir animasyon çerçevesi geliştirdim! Bunu kullanarak bu animasyon kolayca oluşturulabilir:

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

basitçe ayarlanmış bu animasyonu durdurmak niliçin endlessRotater.

Eğer ilgileniyorsanız, lütfen bir göz atın: https://github.com/hip4yes/Animatics


1

Swift 4 ,

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

Ref


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

Ana Kare Animasyonlarını kullanarak Swift 5 UIView Uzantısı

Bu yaklaşım, doğrudan UIView.AnimationOptions.repeat komutunu kullanmamızı sağlar.

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
Senden hoşlanıyorum, oldukça temiz
Nicolas Manzini

0

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


    }

0

Hızlı 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

UIVIewKategori eklemeniz iyi olur :

#import <QuartzCore/QuartzCore.h>
#import "UIView+Rotate.h"

Uygulama UIView (Döndür)

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

Bu yöntemleri kullanmamak :)

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

Aferin. Sadece UIImageView kategorisine yorum yapmak istiyorum. Hepinize aynı teşekkürler.
Zgpeace
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.