Rotating Wheel with labels - how to keep labels horizontal as the wheels rotates?

713 Views Asked by At

I have been searching for a solution of how to implement a wheel of fortune-type wheel (working well) with the exception that I need the images/labels on the periphery of the wheel to stay horizontal and not rotate with the wheel. I have the following implemented, but the labels ( in this case the red ovals ) aren't staying horizontal.

This is how it should always look, no matter where the wheel has rotated

enter image description here

I am enclosing my code that builds the red ovals on the screen :

CGFloat cita = 0;
for(int i = 1; i < 2; ++i)
{
    CGFloat smallCircleRadius = bigCircleRadius / 8.0;
    for (int i = 0; i < 8; i++)
    {

        CGPoint smallCircleCenter = CGPointMake(wheelCenter.x  + bigCircleRadius * cos(cita) - smallCircleRadius/2.0 , wheelCenter.y + bigCircleRadius * sin(cita) - smallCircleRadius / 2.0 );


        CGRect smallCircleRect = CGRectMake(smallCircleCenter.x,smallCircleCenter.y,smallCircleRadius * 2,smallCircleRadius);

        cita += M_PI / 4.0;

        CAShapeLayer *l = [CAShapeLayer layer];
        UIBezierPath * p1 = [UIBezierPath bezierPathWithOvalInRect:smallCircleRect];

        l.path = p1.CGPath;
        l.strokeColor = [[UIColor redColor] CGColor];
        l.fillColor = [[UIColor redColor] CGColor];
        l.lineWidth = 3.0;

        l.anchorPoint = CGPointMake(.5, .5);

        [self.emoticonsArray addObject:l];

        [self.baseWheel.layer addSublayer:l];

      }

   }

Below is the function that spins the wheel; I'm making the line of code that does the rotation for the labels - I'm obviously doing something wrong here, but I have no idea what. Any guidance greatly appreciated.

-(void)spin:(double)delta
{
currentAngle = currentAngle + delta;

CATransform3D transform = CATransform3DMakeRotation(currentAngle, 0, 0, 1);

[self.baseWheel.layer setTransform:transform];

  // rotate the red labels here.
  for (CAShapeLayer * l in self.emoticonsArray)
  {

    CGPoint miniWheelCenter = [l convertPoint:l.position toLayer:self.baseWheel.layer.superlayer];


    // !! something wrong here!! but what? 
    CATransform3D t_l = CATransform3DMakeRotation(-currentAngle, miniWheelCenter.x/2, miniWheelCenter.y/2, 1);
    [l setTransform:t_l];
  }
}
3

There are 3 best solutions below

1
santhu On

the problem is because you are rotating the entire wheel for which those lables are subViews.so along with wheel they also rotate.
The best approach is calculate the rotation angle value.From that angle, calculate new positions of labels on that circle, and place lables(not subivews of wheel) in those new postions.

OR (method 2)

set the negative of that rotation transform to those labels.

4
Prince Agrawal On

Other way you can get rid of this issue is, Don't use labels as subView of the wheel. You just place them on top of the wheel. So when the wheel rotates, labels would be on same place. Let me know if I am not clear enough

EDIT

Here is an alternate solution for your problem. It's not perfect, but might give you a new direction to think.

  1. Take your wheel image in png format.
  2. make the background transparent for your wheel. (Not needed.. just to beautify)
  3. make a hole in the positions on wheel where you want to show label. (By hole I meant to make the portion transparent).
  4. Now put Labels behind the wheel.Position them according to required rotation angle.
  5. Now when you rotate the wheel, at exact angles, you would be able to see the labels. Its just like two layers of paper.

Why It is not Perfect Labels will not be moving with wheel. So you would be able to see labels only at certain angles only.

I don't know the exact purpose behind requirement of your question, but I used this approach to create Jog dial for my app..

2
rob mayoff On

The arguments to CATransform3DMakeRotation are the angle and the three components of the axis of rotation. The axis of rotation for both the wheel and the label sublayers should simply be the Z axis. You got this right for the wheel but wrong for the labels.

CATransform3D t_l = CATransform3DMakeRotation(-currentAngle, 0, 0, 1);
[l setTransform:t_l];

However, it would be simpler to just use affine transforms, which can only rotate around the Z axis:

-(void)spin:(double)delta {
    currentAngle = currentAngle + delta;
    self.baseWheel.layer.affineTransform = CGAffineTransformMakeRotation(currentAngle);

    CGAffineTransform labelTransform = CGAffineTransformMakeRotation(-currentAngle);
    for (CAShapeLayer *l in self.emoticonsArray) {
        l.affineTransform = labelTransform;
    }
}

Core Animation will convert the affine transforms to 3D transforms for you.