Background:
I want to show a label that is rotated 90 degrees clockwise. The rotated label should be in a certain frame that I specify. Let's say (10, 100, 50, 100).
I know that I can rotate a view by using CGAffineTransform
. I also know that I should not set the frame
property after a transformation is done, according to the docs.
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.
I tried to set the frame after the transform and although it worked, I don't want to do something that the docs told me not to.
label2.transform = CGAffineTransform(rotationAngle: -.pi / 2)
label2.frame = CGRect(x: 10, y: 100, width: 50, height: 100)
Then I thought, I could do this:
CGRect
of the frame that I wantAnd then the label would be in the desired frame.
So I tried something like this:
let desiredFrame = CGRect(x: 10, y: 100, width: 50, height: 100) // step 1
// I am using UIViews here because I am just looking at their frames
// whether it is a UIView or UILabel does not matter
// label1 is a view that is in the desired frame but not rotated
// If label2 has the correct frame, it should completely cover label1
let label1 = UIView(frame: desiredFrame)
let label2Frame = rotateRect(label1.frame) // step 2
let label2 = UIView(frame: label2Frame) // step 3
view.addSubview(label1)
view.addSubview(label2)
label1.backgroundColor = .red
label2.backgroundColor = .blue
label2.transform = CGAffineTransform(rotationAngle: -.pi / 2) // step 4
Where rotateRect
is declared like this:
func rotateRect(_ rect: CGRect) -> CGRect {
return rect.applying(CGAffineTransform(rotationAngle: .pi / 2))
}
This didn't work. label2
does not overlap label1
at all. I can't even see label2
at all on the screen.
I suspect that this is because the applying
method in CGRect
rotates the rect about the origin, instead of the centre of the rect. So I tried to first transform the rect to the origin, rotate it, then transform it back, as this post on math.SE said:
func rotateRect(_ rect: CGRect) -> CGRect {
let x = rect.x
let y = rect.y
let transform = CGAffineTransform(translationX: -x, y: -y)
.rotated(by: .pi / 2)
.translatedBy(x: x, y: y)
return rect.applying(transform)
}
However, I still cannot see label2
on the screen.
I think that the order of your transformations are incorrect. If you do it so, that,
Translate(x, y) * Rotate(θ) * Translate(-x, -y)
And using that with your rotateRect
seem to work correctly. Since, you are rotating the view by 90 degrees, the blue view completely block red view. Try it out with some other angle and you shall see effect more prominently.
func rotateRect(_ rect: CGRect) -> CGRect {
let x = rect.midX
let y = rect.midY
let transform = CGAffineTransform(translationX: x, y: y)
.rotated(by: .pi / 2)
.translatedBy(x: -x, y: -y)
return rect.applying(transform)
}