vgmoose vgmoose - 2 months ago 16
Swift Question

Weird squishing when updating UIImageView frame after rotating with CGAffineTransform

I have two buttons and one UIImageView in my main view. One button tries to rotate the UIImageView by 30 degrees, and the other updates the frame of the UIImageView to itself.

I wouldn't expect setting the frame to itself to affect anything visually, but it instead seems to "squish" the image if it's in any rotation other than the default orientation. I stumbled upon this, as I wanted to update the UIImageView's frame in order to change its x and y coordinates after rotating.

As a result, the rotate button seems to work fine as long as I never push the update frame button. If I push the second button while the view is ever rotated, however, it squishes the image into a state that I don't understand, or know how to undo.

Video of the second button "squishing" the image:
https://streamable.com/ba7zd

Video of the second button only "squishing" while the rotation isn't the default orientation: https://streamable.com/vo3cd

What's the reason that this is happening? This question and this question both seem to capture a similar scenario, but I'm unsure how to apply either solution.

In the ViewController:

@IBOutlet weak var dog: UIImageView!

@IBAction func breakRotate(_ sender: UIButton) {
self.dog.frame = self.dog.frame // squishes if rotated
}

@IBAction func rotateDog(_ sender: UIButton) {
UIView.animate(withDuration: 1.5, delay: 0, options: [.allowUserInteraction], animations: {
self.dog!.transform = self.dog!.transform.rotated(by: CGFloat(0.523599)) // 30 degrees in radians
})
}


Image:

enter image description here

Answer Source

The value returned from frame property after applying a rotation is not the rotated frame, It is the minimum bounding rectangle that encloses the view, which can be different in size from the actual frame. (The documentation says the frame will be undefined and should be ignored but in reality it's returning the minimum bounding rect)

When you apply a transform to a view you should not change the frame because it can interfere with the transformation.

If you want to change the position after transformation you should change the center property of the view:

dog.center = newCenterPoint

Finally as for why you are seeing that unusual effect, when you do the transform it automatically takes care of resizing the frame to the new minimum bounding rect without messing up the size of your image, but when you apply that new changed frame back to the view it won't know that this is the result of a transform and will try to resize your image and that's why your image is getting squished like that.