1

I want to create a sort of "iPod Wheel" control in a Swift project that I'm doing. I've got everything drawn out, but not it's time to actually make this thing work.

iPod Style Wheel

What would be the best way to recognize "spinning" so to speak, or to describe that more clearly, when the user is actively pressing the wheel and spinning his/her thumb around the wheel in a clockwise or counter-clockwise direction.

I will no doubt want to use touchesBegan/touchesMoved/touchesEnded. What's the best way to figure out spinning though?

I'm thinking

a) determine in touchesMoved if the users touch is within circle, by determining the radius from the center point. Center point and radius are easily obtainable. Using these however, how can I determine the outer edge of the circle/wheel... to know whether the user is within the actually circle (their touch could still be in the view, but outside the actual wheel portion)

b) Determine the current angle and how it has changed the previous angle. By that I mean... I would use the center point of the circle as one point, and the users current touch as the second point. This gives me my vector. I would also have a baseline angle. Likely center point to 12 c'clock. I would compare the two vectors (I already have a VectorMath class for this from something else I'm doing) and see my angle is 0. If the users touch were at 3 oclock, and I compared it to our baseline angle... I would see the angle is 90 degrees. I would continually calculate the angle, and perhaps every 5 degrees of change... would warrant a change in the controls output (depending on desired sensitivity).

Does this seem like the best way to do this? I think this would be an ideal way, but am still not sure on how to calculate the circles outer edge, and determine if a users touch is within it.

Mihriban Minaz
  • 3,043
  • 2
  • 32
  • 52
chris P
  • 6,359
  • 11
  • 40
  • 84

3 Answers3

2

You are on the right track. I think approach b) will work.

  1. Remember the starting position of the finger at the touchesBegan event.

  2. Imagine a line from the finger position to the middle of the button circle.

  3. For the touchesMoved event, again, imagine a virtual line from the new position to the center of the circle.

  4. Using the formula from http://mathworld.wolfram.com/Line-LineAngle.html (or some code) you can determine the angle between the two lines. If it's a negative angle the user is turning the wheel counter-clockwise, otherwise it's clockwise.

To determine if the touch event was inside the ring, calculate the distance from the center of the circle to the point of touch. It should be between the minimum and the maximum distance (inner circle and outer circle radius). Calculating the distance between to two points is explained at https://www.mathsisfun.com/algebra/distance-2-points.html

neuhaus
  • 3,886
  • 1
  • 10
  • 27
1

I think you're almost there, although I'd do something slightly different on your point b.

If you think about it, when you start "spinning" on your iPod, you don't need to start from a precise position, you start spinning from "where you started", therefore I wouldn't set my "baseline angle" at π/2, I'd set my baseline (or 0°) angle at the point the user taps for the first time, and starting from then, I'd count the offset angles, clockwise and counterclockwise. I don't think there would be much difference, except maybe from some calculations you'll do on the angles, on the two approaches, practically speaking; it just makes more sense imho to start counting from the first input rater than setting a baseline to π/2 and counting the first angle.

dev_mush
  • 2,136
  • 3
  • 22
  • 38
0

I am answering in parts.

// Get a position based on the angle
      float xPosition = center.x + (radiusX * sinf(angleInRadians)) - (CGRectGetWidth([cell frame]) / 2);
      float yPosition = center.y + (radiusY * cosf(angleInRadians)) - (CGRectGetHeight([cell frame]) / 2);

      float scale = 0.75f + 0.25f * (cosf(angleInRadians) + 1.0);

next

[cell setTransform:CGAffineTransformScale(CGAffineTransformMakeTranslation(xPosition, yPosition), scale, scale)];
         // Tweak alpha using the same system as applied for scale, this
         // time with 0.3 the minimum and a semicircle range of 0.5
         [cell setAlpha:(0.3f + 0.5f * (cosf(angleInRadians) + 1.0))];

and

- (void)spin:(SpinGestureRecognizer *)recognizer
{
   CGFloat angleInRadians = -[recognizer rotation];
   CGFloat degrees = 180.0 * angleInRadians / M_PI;   // Radians to degrees
   [self setCurrentAngle:[self currentAngle] + degrees];
   [self setAngle:[self currentAngle]];
}

again check the wheelview.m of photowheel in github.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Kumar Utsav
  • 2,761
  • 4
  • 24
  • 38