8

I an trying to animate a UIImageView to rotate counter clockwise when a user touches it and moves its finger on it in clockwise direction.
Basically I want the UIImageView to go back to its original position once the touch ends and it should move in counter clockwise direction.

The problem I have is that every time angle (in degrees) is greater than 180 then the image rotates clockwise back to its original position. Its apparently taking the shortest path back. As for angles 179 degrees or less the image rotate counter clockwise (what i need).

I tried both these pieces of code and they behave the same way. Any suggestions?

NOTE: here angle variable is a double and its initialized to be zero and it remains 0 throughout my code

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [self handleObject:touches withEvent:event isLast:YES];

    /* this doesn't make rotation counter clockwise for rotations greater than 180 */
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationCurve: UIViewAnimationCurveLinear];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationRepeatCount:1]; 
    CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
    circle1ImgVw.transform = CGAffineTransformRotate(transform, angle);
    // ends animation
    [UIView commitAnimations];


    /* this doesn't make rotation counter clockwise for rotations greater than 180 */
    [UIView animateWithDuration:1.0 animations:^{
            circle1ImgVw.transform = CGAffineTransformMakeRotation(angle);
        }];
} 

I tried looking into this post and there are couple of problems with it

  • I cannot touch and rotate the image anymore after the animation is done
  • It always animates in clockwise direction and I haven't been able to figure out how to make it go counter clockwise smoothly from the point where the user ended rotating the image.
Community
  • 1
  • 1
Sam B
  • 27,273
  • 15
  • 84
  • 121
  • ACB - I looked into that post and its not a duplicate. I cannot get it to move counter clockwise! – Sam B Dec 09 '12 at 21:01

2 Answers2

3

I had a similar issue, check the accepted answer out, it might help you:

Rotate a UIView clockwise for an angle greater than 180 degrees


In response to comments, maybe this will help:

In my code I actually use

rotationAnimation.fromValue
rotationAnimation.toValue

instead of

rotationAnimation.byValue.

The rotation is always going to be counter clockwise if the toValue is less than the fromValue. It doesn't matter if your values are positive or negative, only the relation between them.

Figure out what your starting angle is, figure out which direction you want to rotate and figure out what your ending angle is. Make sure that it's less than your starting angle if you want to go counter clockwise. Here is the code I use for animating a clock hand clockwise from 12:00 to the current time.

-(void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [self updateClockArmAngle];
}

- (void)updateClockArmAngle
{
    // Get the time
    NSDate *date = [NSDate date];
    NSCalendar* calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
    [calendar setTimeZone:[NSTimeZone timeZoneWithName:@"America/Toronto"]];
    NSDateComponents* components = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:date];

    CGFloat hour = [components hour];
    CGFloat angle = (hour/24.0)*(2*M_PI);

    CGFloat minute = [components minute];
    angle += (minute/(24*60))*(2*M_PI);

    [self rotateViewAnimated:self.clockArm withDuration:1.5 byAngle:angle];
}


- (void) rotateViewAnimated:(UIView*)view
               withDuration:(CFTimeInterval)duration
                    byAngle:(CGFloat)angle
{    
    CABasicAnimation *rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.fromValue = 0;
    rotationAnimation.toValue = [NSNumber numberWithFloat:angle];
    rotationAnimation.duration = duration;
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [rotationAnimation setRemovedOnCompletion:NO];
    [rotationAnimation setFillMode:kCAFillModeForwards];
    [view.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}
Community
  • 1
  • 1
Darren
  • 10,091
  • 18
  • 65
  • 108
  • I tested this code in my app and it always moves clockwise. I can't seem to figure out from that post how to move it counter clockwise – Sam B Dec 09 '12 at 21:02
  • By the way, if I add "angle = angle * -1;" in that void function it does rotate counter clockwise but for angles greater than 180 it goes back to its clockwise rotation again. – Sam B Dec 09 '12 at 21:27
  • Set the angle to negative and it rotates counter clockwise. – Darren Dec 09 '12 at 21:29
  • see my comments above yours – Sam B Dec 09 '12 at 21:31
  • Hmm, for me it still goes counter clockwise for negative angles above 180.(ie. angle < -180). The angle is given in radians though, not degrees. – Darren Dec 09 '12 at 21:31
  • There is an image in my post - http://stackoverflow.com/questions/13790042/rotary-dial-rotation-limitation use that and you will see my dilemma – Sam B Dec 09 '12 at 21:36
  • Looks cool. I'm fairly sure that using the method provided in the answer, if the angle given is negative the rotation will always be counter clockwise. I tested it with angles of <-360 and I was still getting ccw rotation. I think you just need to figure out the direction you want to rotate, and then make sure the angle you give is the appropriate one. My guess is when you were seeing clockwise rotation, the original angle was negative, so multiplying it by -1 made it positive. – Darren Dec 09 '12 at 23:02
  • I tried it. if (angle < (0+0.001)){}else{angle = angle * -1;} I made sure the angle was negative and it does counter rotate UIImageVw but it stops at an arbitrary point. The image never comes to reset back where it started. I think it has something to do with rotationAnimation.byValue = [NSNumber numberWithFloat:angle]; or view.transform = CGAffineTransformRotate(view.transform, angle); but I am not sure exactly what? – Sam B Dec 09 '12 at 23:36
  • Thanks for the code buddy. Seriously, it doesn't work for me i.e. my starting angle is always 0. If I plug that in [self rotateViewAnimated:self.clockArm withDuration:1.5 byAngle:0.000]; it doesn't do anything. All I am trying to do is once the image is rotated, let it come to rest back where it started by moving back in counter clockwise direction. Thanks for making an effort though. – Sam B Dec 10 '12 at 05:04
  • @SamBudda -- One thing you may need to do is to turn off "Autoresize Subviews" in the outermost UIView of your screen design. This does all sorts of bad things to rotated images. – Hot Licks Dec 11 '12 at 20:42
  • @SamBudda -- Also keep in mind that if you've rotated the image to get to its current state, what you'll be doing is "unrotating" it to get back to the initial state -- ie, your starting angle is where the initial CW rotation left it and you're rotating CCW back to zero degrees. – Hot Licks Dec 11 '12 at 20:44
0

The technique I've used is to divide the rotation angle by 2 and separate the rotate into two separate animations, linked by the completion: parameter of animateWithDuration:delay:options:animations:completion:. But, since the view has been rotated to its current position, you need to start with that position and "unrotate" back to zero, vs attempting to rotate CCW from zero.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • I've tried this, but I was never able to get a smooth animation, even using UIViewAnimationOptionCurveLinear. Are you able to get a smooth animation this way? – Darren Dec 11 '12 at 22:12
  • It seemed perfectly smooth (I was surprised, in fact). Be sure to NOT include any delay in the second rotation, and have your transform pre-computed. – Hot Licks Dec 11 '12 at 23:51
  • I was doing just as you said, but if it worked for you I must have been doing something wrong. Good to know that this can work. – Darren Dec 12 '12 at 00:53
  • 1
    @Darren - One thing you probably don't want to do is put the entire second animation in the `completion:` clause of the first animation. Instead have it call a method to do the second half. – Hot Licks Dec 12 '12 at 03:48
  • Maybe that's what I was doing wrong, because that's how I had it. Why would that make a difference? – Darren Dec 12 '12 at 03:55
  • @Darren - Blocks have some scary data linkage issues. I can't point at a specific reason, but it seemed unwise when I was coding this. – Hot Licks Dec 12 '12 at 04:36
  • darren - see my answer with full code. Its a little timer trick i play to get a smooth counter clockwise rotation. Of course you can use this same code to do smooth clockwise rotation too. – Sam B Dec 17 '12 at 17:37