views:

119

answers:

2

I'm looking for a tutorial or any hint on how you would build a spinning wheel that can be rotated in both directions with your finger and snaps to specific points. I have looked into basic animations but stuck on the user interaction side.

Any hint is highly appreciated.

+4  A: 

Fundamentally you just need to perform a rotate transform on a UIImageView where the angle of rotation is controlled by tracking your finger. I posted a snippet about this for similar question.

Broadly, atan2() will give you the vector angle from the designated centre of the wheel image, so for a touch event at (x,y), the current angle would be atan2(y-cy,x-cx) where (cx,cy) is the centre of the wheel. Track changes in this angle for the delta, so you know how much to rotate the wheel by when the user's finger moves.

Snapping the wheel for a ratchet effect at its simplest requires the delta angle to be clamped to zero until it exceeds a certain threshold. Of course, if you want the ratchet effect to look very realistic, with proper acceleration and deceleration, that's another matter and you should consult a good physics book or website.

Echelon
+1  A: 

I've implemented something similar, atan2 function as mentioned by Echelon helped me a lot.

I have a custom view that contains a layer which can be rotated around the middle of the view. I'm actually creating more layers as I have graphics which are overlapping the wheel. The view itself does not draw anything, it is used as a container for layers, and for the sake of reacting to touch events.

In the touchesEnded:withEvent: I'm creating more complex animation that auto-rotates the wheel to aligned position.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchedUnderAngle = [self angleForTouch:[touches anyObject]];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    double angle = [self angleForTouch:[touches anyObject]];
    wheelAngle = wheelAngle - angle + touchedUnderAngle;
    touchedUnderAngle = angle;

    [CATransaction begin];
    [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    [CATransaction setAnimationDuration:0.05];
    self.wheelLayer.transform = CATransform3DMakeRotation(wheelAngle, 0.0f, 0.0f, 1.0f);
    [CATransaction commit];
}

- (double)angleForTouch:(UITouch*)touch
{
    CGPoint location = [touch locationInView:self];

    double x = location.x - self.frame.size.width / 2;
    double y = self.frame.size.height / 2 - location.y;
    return atan2(y, x);
}
Michal