Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate a UIView clockwise for an angle greater than 180 degrees

I'm animating a clock arm from pointing towards 12 o'clock to the current time. If it is say, 11 o'clock, I want the arm to rotate clockwise to the 11 o'clock position. But of course if I use:

 CGAffineTransform rotation = CGAffineTransformMakeRotation(2*M_PI*11/12);

 [UIView animateWithDuration:3.0
                  animations:^{
                         clockArm.transform = rotation;
                     }];

the rotation goes counterclockwise. I tried:

CGFloat angle = 2*M_PI*11/12;
CGAffineTransform firstRotation = CGAffineTransformMakeRotation(M_PI-0.001);
CGFloat firstRotationTime = 3.0*(M_PI/angle);
CGAffineTransform secondRotation = CGAffineTransformMakeRotation(angle);
CGFloat secondRotationTime = 3.0 - firstRotationTime;

[UIView animateWithDuration:firstRotationTime
                      delay:0.0
                    options:UIViewAnimationCurveLinear
                 animations:^{
                         self.clockArm1.transform = firstRotation;
                     }
                 completion:^(BOOL finished) {
                     [UIView animateWithDuration:secondRotationTime
                                           delay:0.0
                                         options:UIViewAnimationCurveLinear
                                      animations:^{
                                          self.clockArm1.transform = secondRotation;
                                      }
                                      completion:^(BOOL finished){
                                      }];
                 }];

The animation does go clockwise, but it is choppy - the animation still seems to be doing a UIViewAnimationEaseInOut for the first animation. What am I doing wrong, or is there another way to accomplish what I want?

like image 592
Darren Avatar asked Oct 10 '12 17:10

Darren


2 Answers

You can use the completion block of CATransaction to set the rotation property of the view when the animation has finished. The following function worked in my test case:

- (void) rotateViewAnimated:(UIView*)view
               withDuration:(CFTimeInterval)duration
                    byAngle:(CGFloat)angle
{
    [CATransaction begin];
    CABasicAnimation *rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.byValue = [NSNumber numberWithFloat:angle];
    rotationAnimation.duration = duration;
    rotationAnimation.removedOnCompletion = YES;

    [CATransaction setCompletionBlock:^{
        view.transform = CGAffineTransformRotate(view.transform, angle);
    }];

    [view.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    [CATransaction commit];
}

You use it like

[self rotateViewAnimated:self.clockArm1 withDuration:3.0 byAngle:2*M_PI*11./12.];
like image 62
Martin R Avatar answered Nov 15 '22 07:11

Martin R


Thanks for @Martin R 's accepted answer. I edited a bit:

I replaced this line

rotationAnimation.removedOnCompletion = YES;

with these two lines:

rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;

Then, in the CompletionBlock, I added one more line:

[view.layer removeAllAnimations];

So, the code finally becomes:

    - (void) rotateViewAnimated:(UIView*)view
           withDuration:(CFTimeInterval)duration
                byAngle:(CGFloat)angle
    {
        [CATransaction begin];
        CABasicAnimation *rotationAnimation;
        rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        rotationAnimation.byValue = [NSNumber numberWithFloat:angle];
        rotationAnimation.duration = duration;
        // changed by me
        rotationAnimation.removedOnCompletion = NO;
        rotationAnimation.fillMode = kCAFillModeForwards;


        [CATransaction setCompletionBlock:^{
        view.transform = CGAffineTransformRotate(view.transform, angle);
        // added by me
        [view.layer removeAllAnimations]; // this is important

        }];

    [view.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    [CATransaction commit];

    }

My references are from:

1, https://stackoverflow.com/a/3586433/2481444

2, After rotating a CALayer using CABasicAnimation the layer jumps back to it's unrotated position

like image 21
Yang Avatar answered Nov 15 '22 08:11

Yang