如何围绕其中心旋转CGRect?

时间:2019-03-02 08:58:13

标签: ios swift cgaffinetransform cgrect

背景:

我想显示一个顺时针旋转90度的标签。旋转后的标签应位于我指定的特定框架中。假设是(10,100,50,100)。

我知道我可以使用CGAffineTransform来旋转视图。根据{{​​3}},我也知道我不应该在完成转换后设置frame属性。

  

如果此属性的值不是恒等变换,则frame属性中的值是未定义的,应忽略。

我尝试在转换后设置框架,尽管它可以工作,但是我不想做文档告诉我不要做的事情。

label2.transform = CGAffineTransform(rotationAngle: -.pi / 2)
label2.frame =  CGRect(x: 10, y: 100, width: 50, height: 100)

然后我想,我可以这样做:

  1. 创建我想要的框架的CGRect
  2. 将其逆时针旋转90度
  3. 将该矩形设置为标签框架
  4. 将标签顺时针旋转90度

然后标签将位于所需的帧中。

所以我尝试了这样的事情:

    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

rotateRect的声明如下:

func rotateRect(_ rect: CGRect) -> CGRect {
    return rect.applying(CGAffineTransform(rotationAngle: .pi / 2))
}

这没有用。 label2根本不与label1重叠。我什至在屏幕上都看不到label2

我怀疑这是因为applying中的CGRect方法使矩形绕原点旋转,而不是矩形的中心旋转。因此,我尝试首先将rect转换为原点,旋转它,然后再将其转换回,如math.SE上的docs所述:

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)
}

但是,我仍然无法在屏幕上看到label2

2 个答案:

答案 0 :(得分:1)

我认为您的转换顺序不正确。如果这样做的话,

  

平移(x,y)*旋转(θ)*平移(-x,-y)

并与您的rotateRect一起使用似乎正常。因为您将视图旋转了90度,所以蓝色视图完全阻止了红色视图。以其他角度尝试一下,您会更加明显地看到效果。

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)
}

答案 1 :(得分:0)

由于我只想将视图旋转90度,因此初始框架的宽度和高度将与旋转框架的宽度和高度相反。

初始帧的中心和旋转的中心相同,因此我们可以在变换之前将标签的center设置为所需帧的中心。

    let desiredFrame = CGRect(x: 10, y: 100, width: 50, height: 100)
    let label1 = UIView(frame: desiredFrame)
    // get the centre of the desired frame
    // this is also equal to label1.center
    let center = CGPoint(x: desiredFrame.midX, y: desiredFrame.midY)
    let label2Frame = CGRect(x: 0, y: 0, width: desiredFrame.height, height: desiredFrame.width)
    let label2 = UIView(frame: label2Frame)
    view.addSubview(label1)
    view.addSubview(label2)
    label1.backgroundColor = .red
    label2.backgroundColor = .blue
    label2.center = center // set the centre of label2 before the transform
    label2.transform = CGAffineTransform(rotationAngle: -.pi / 2)