Rotate UIImageView clockwise

2020-05-21 04:34发布

问题:

This should be simple, but I'm having trouble rotating a UIImageView a full 360 degrees, repeated forever.

[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState animations:^{
    self.reloadButton.imageView.transform = CGAffineTransformRotate(self.reloadButton.imageView.transform, -M_PI);
} completion:^(BOOL finished) {

}];

According to the docs, the signedness of the angle I pass to CGAffineTransformRotate determines the direction of the rotation, but the above code rotates counterclockwise. Same with M_PI.

The angle, in radians, by which this matrix rotates the coordinate system axes. In iOS, a positive value specifies counterclockwise rotation and a negative value specifies clockwise rotation. In Mac OS X, a positive value specifies clockwise rotation and a negative value specifies counterclockwise rotation.

回答1:

Christoph is already going the correct way, but there is a far better way to keep it spinning without reinvoke it in the animation delegates every time it ends. This is simply wrong.

Just set the repeatCount property of your animation to HUGE_VALF.

CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.fromValue = @0.0f;
animation.toValue = @(2*M_PI);
animation.duration = 0.5f;             // this might be too fast
animation.repeatCount = HUGE_VALF;     // HUGE_VALF is defined in math.h so import it
[self.reloadButton.imageView.layer addAnimation:animation forKey:@"rotation"];

As stated in the documentation, this will cause the animation to repeat forever.



回答2:

Sorry missed first part, view rotates just fine using smaller angle:

[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveLinear | UIViewAnimationOptionBeginFromCurrentState animations:^{
        redView.transform = CGAffineTransformRotate(redView.transform, M_PI_2);
    } completion:^(BOOL finished) {

    }];

I couldn't find any meaningful explanations why it fails with M_PI.



回答3:

I encountered the same issue a while ago. I do not remember the reason for that issue, but this is my solution:

/**
 * Incrementally rotated the arrow view by a given angle.
 *
 * @param degrees Angle in degrees.
 * @param duration Duration of the rotation animation.
 */
- (void)rotateArrowViewByAngle:(CGFloat)degrees
                  withDuration:(NSTimeInterval)duration {

    CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    spinAnimation.fromValue = [NSNumber numberWithFloat:self.currentAngle / 180.0 * M_PI];
    spinAnimation.toValue = [NSNumber numberWithFloat:degrees / 180.0 * M_PI];
    spinAnimation.duration = duration;
    spinAnimation.cumulative = YES;
    spinAnimation.additive = YES;
    spinAnimation.removedOnCompletion = NO;
    spinAnimation.delegate = self;
    spinAnimation.fillMode = kCAFillModeForwards;

    [self.arrowView.layer addAnimation:spinAnimation forKey:@"spinAnimation"];

    self.currentAngle = degrees;
}

and then you can use the delegate methods

- (void)animationDidStart:(CAAnimation *)theAnimation
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

to rotate keep it rotating. Also, degree and duration parameters can be really high numbers... if this is enough.

UPDATE:
As stated by yinkou,

spinAnimation.repeatCount = HUGE_VALF;     // HUGE_VALF is defined in math.h so import it 

is way better that restarting the animation in the delegate.

PLEASE NOTE:
self.currentAngle is a property remembering the current final rotation.
I needed that to make the view rotate left and right way around.



回答4:

I wrote UIImageView category for this: https://gist.github.com/alexhajdu/5658543.

Just use:

[_myImageView rotate360WithDuration:1.0 repeatCount:0]; //0 for infinite loop