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다시 시작하기 전에도.

답변:


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 2016 년

3
QuartzCore.framework 추가 프로젝트-> 빌드 단계
gjpc

9
이것은 iOS 3.0 이하의 올바른 코드이지만, 새로운 프로그래머와 새로운 프로젝트의 경우 Apple은 이제 Docs & @Nate 코드에서 이러한 방법을 사용하지 않도록 경고합니다. Apple은 현재 선호하는 블록 기반 애니메이션을 사용합니다.
PaulWoodIII

1
@cvsguimaraes 문서에서 : "속성 값이 이전 반복주기의 끝 값에 현재 반복주기 값을 더한 것인지 결정합니다."
smad

12
이것은 도움이 될 수 있습니다. [view.layer removeAllAnimations]; 필요할 때 애니메이션을 중지합니다.
arunit21

112

아이디어에 대한 Richard J. Ross III의 의견이지만 그의 코드가 내가 필요하지 않은 것을 발견했습니다. 에 대한 기본값 은 연속 애니메이션에서 제대로 보이지 않는 options을 제공하는 것 UIViewAnimationOptionCurveEaseInOut입니다. 또한 필요한 경우 ( 무한 이 아니라 무한한 지속 시간) 1/4 회전으로 애니메이션을 중지 하고 처음 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

1
@Dilip 교체 M_PI / 2와 함께 - (M_PI / 2). (각 줄의 끝을 보려면 오른쪽으로 코드를 스크롤하십시오)
Nate

1
@ Dilip, 코드에서 사용하는 기간을 모르겠습니다. 0.5내가 90도 당 같은 초? 그렇다면, 내 코드는 당신이 정차하지 않는 부분 90도 회전. 전체 90도 간격으로 멈출 수 있지만 "필요한"90도 회전을 하나 더 추가합니다. 따라서 위 코드에서 stopSpin0.35 초 후에 호출하면 다시 0.65 초 동안 회전하고 총 180도 회전에서 멈 춥니 다. 더 자세한 질문이 있으면 새로운 질문을 열어야 할 것입니다. 이 답변에 자유롭게 연결하십시오.
Nate

1
@MohitJethwa, 무슨 일이 일어나고 있습니까? 이것을 사용하는 앱이 있으며 iOS 8.1에서 여전히 작동합니다.
Nate

1
@ Heemang, 물론, 그것은이 질문이 아닙니다. 이것이 당신이하려는 일이라면 새로운 질문을 게시 할 것입니다.
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 란 무엇입니까?
루다

애니메이션을 식별하고 검색하는 데 도움이되는 상수 문자열 키입니다. 원하는 문자열이 될 수 있습니다. 제거 과정에서 애니메이션이 검색되고이 키로 삭제 된 것을 볼 수 있습니다.
Kádi

문자열입니까 아니면 특정한 것입니까?
루다

답이 늦어서 미안하지만 네, 어떤 문자열이든 가능합니다.
Kádi

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'를 사용했습니다. 이렇게하면 애니메이션 중에 뷰가 점프하거나 재설정되지 않습니다.

또 다른 것은 '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을 생성하여 매번 반대 방향으로 뷰를 변환합니다 (Note-Nate의 대답은 변환의 라디안 값을 M_PI로 변경하면이 문제가 발생합니다). 360도 변환은 단순히 뷰를 원래 위치에 유지하도록 요구하므로 회전이 전혀 표시되지 않습니다.


내 대답의 핵심은 (그리고 그로부터 파생되는 Richard의 대답) 방향 전환을 피하기 위해 90도 단계 를 사용하는 것 입니다. 많은 이미지는 180도 또는 90도 대칭이기 때문에 회전을 중지하려는 경우 90 도는 비교적 잘 작동합니다 .
Nate

네, 방금 왜 사용되는지 설명 할 줄 알았는데 :)
ram

2
@nik 그러나 거기에 중단 점을 설정하면 완료 블록이 시스템에 의해 호출되기 때문에 스택 오버플로가 발생하지 않는다는 것을 알았 rotateImageView습니다. 그런 의미에서 재귀 적이 지 않습니다.
huggie

1
원하는 기능을 가진 작은 버전의 코드에 대해 좋은 대답 +1.
Pradeep Mittal

1
UIViewAnimationOptionRepeat를 사용하지 않는 이유에 대한 설명에 정말 감사했습니다.
Jonathan Zhan

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로 돌아 오면 "점프"합니다.

회전 방향을 변경하려면 부호 angle( angle *= -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

@AlexPretzlav UIViewAnimationOptionRepeat애니메이션에서 설정 했는지 확인하십시오 options.
levigroker

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.
Mr Rogers

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에서) 나를 위해 아주 잘 작동했습니다. 감사합니다!
agrippa

나는 당신의 단순 좋아
니콜라스 만지니

10

1/4 회전을 사용하고 회전을 점차적으로 증가시킵니다.

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 (^ const__strong ()'을 'void (^) (BOOL)'유형의 매개 변수로 보내는 호환되지 않는 블록 포인터 유형을 던졌습니다. 코드에서 회전 방법을 변경하려고했습니다. 내 질문에 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, 수학은 프로그래밍과 같습니다. 여러 방법으로 같은 일을 할 수 있습니다. 그렇다고 한 가지 방법 만 정확하고 다른 방법은 그렇지 않다는 의미는 아닙니다. 그렇습니다. 모든 방법에 대해 찬반 양론이있을 수 있지만 그렇다고해서 누군가의 프로그래밍 방법에 대해 의문을 제기 할 수있는 것은 아닙니다.이 방법에 대한 찬성과 제안을 할 수 있습니다. 이 의견은 정말 모욕적이므로 이와 같은 의견을 추가해서는 안됩니다.
Dilip

1
유감스럽게도 Dilip을 화나게해서 죄송하지만 2 * M_PI를 쓰는 것은 ((360 * M_PI) / 180)보다 객관적으로 더 명확하며, 후자를 쓰는 것은 당면한 주제에 대한 이해가 부족함을 나타냅니다.
BreadicalMD

1
@BreadicalMD 걱정은 없지만 좋은 제안은 코드를 업데이트했습니다. 고맙습니다.
Dilip

9

다음은 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")
    }

}

9

스위프트 3 버전 :

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 / 30s?
alecail 2018 년

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

1
깃발은 어때요? 따라서, 당신은 애니메이션을 멈추게하는 기능을 가지고있을 것입니다 : var stop = false private func stopRotation() { stop = true } 그렇다면, inside 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 ,

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

심판


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
나는 당신처럼, 꽤 너무 청소
니콜라스 만지니

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.