2

I have a custom view, which I use for markup (draw lines and other figures on it). The view controller recognizes touches and gestures and passes info to the view so it can draw itself properly. Each figure has a label (CATextLayer) with some figure info on it (line length for example).

I added a rotation gesture recognizer to the view controller to rotate this drawing view. I want to rotate the view, but prevent labels from rotation (so they stay 0.0 degrees relative to the superview). For this I calculate the new drawing view's angle relative to the superview and set label's angle property to the negative value, so I can rotate them oppositely. For example, the view is rotated 30 degrees, then I rotate labels -30 degrees.

In the view drawing method which is responsible for drawing figures and setting the labels, I create new transform for each label each time the view needs to be redrawn:

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformRotate(transform, self.angle); //self.angle - rotation angle in radians
transform = CGAffineTransformScale(transform, scale, scale); //scale label (need this for pinch gesture, works as expected)
label.transform = transform;

All this stuff works if I rotate labels 90 degrees. If the degree is not 0, 90, 180, etc, the label's frame changes: shrinks or enlarges, with large angles it even disappears. I understand, that when you rotate the rectangle, it's frame should get bigger as it's pointed here: Why after rotating UIImageView size is getting changed?

Is there a way to prevent CATextLayer from changing its shape when rotating?

Normal position of label: Normal position

When rotated 90 degrees (everything is nice) 90 degrees

Rotated to some arbitrary angle (label frame is misshapen) enlarged label

clemens
  • 16,716
  • 11
  • 50
  • 65
denysowova
  • 111
  • 2
  • 11

2 Answers2

1

The issue was occurring because I was resetting CATextLayer's origin after setting its transform. According to the transform property documentation:

When the value of this property is anything other than the identity transform, the value in the frame property is undefined and should be ignored.

To change the position of a layer, use its position property.

denysowova
  • 111
  • 2
  • 11
0

The frame isn't that what you expected after a non-rectangular rotation.

I see three possible solutions for your problem:

  1. Calculate the correct size of your text, and set the frame by assigning appropriate values to position and bounds.
  2. Create a plain CALayer for the background of each text layer, if the first solution doesn't help.
  3. But it should be much easier if you're rotate the image only and keep the rotation of the text layers unchanged. You can achieve this by adding the text layers to the super layer of the image layer. With this setup you have just to calculate the new position of the text layers after rotation.

I'm very unsure whether the first two solutions are practicable, and I would prefer the third one.

clemens
  • 16,716
  • 11
  • 50
  • 65
  • I just noticed that the bug was caused by resetting labels origin after setting its transform. If I don't change origin, everything works as expected when I rotate the view. But I need to change label's origin, 'cause when I pinch into the view, I scale labels and lines so they remain small. Without resetting label's origin to the line's midpoint, label will "run" away from its line, cause it's getting smaller. Any suggestions on how to fix that? – denysowova Feb 26 '18 at 06:02
  • 1
    @VolodymyrDenysov: You can try to observe the `transform` property of the image layer, and triggering a repositioning of the text layers. – clemens Feb 26 '18 at 06:07
  • I set anchor point to CGPointZero (top left corner of label), seems to work for now, 'cause all the transformations happen around it now. – denysowova Feb 26 '18 at 06:07