【问题标题】:How to find UIView's frame after transform rotating变换旋转后如何找到UIView的框架
【发布时间】:2015-11-02 12:08:32
【问题描述】:

我有一个非常简单的UIImageView,它包含在容器视图中。它们大小相同,没有使用自动布局。当用户按下按钮时,UIImageView 应旋转 90 度。当UIImageView(不是UIImageView.image)旋转时,它应该适合它的superview(.ScaleAspectFit)。 到目前为止,我已经找到了最简单的部分:变换旋转。

    self.currentRotation += 90
    if self.currentRotation >= 360 {
        self.currentRotation = 0
    }

    let angleInRadians: Double
    switch self.currentRotation {
    case 0:
        angleInRadians = 0
    case 90:
        angleInRadians = M_PI_2
    case 180:
        angleInRadians = M_PI
    case 270:
        angleInRadians = M_PI + M_PI_2
    default:
        angleInRadians = 0
        break;
    }
    let newTransform = CGAffineTransformRotate(CGAffineTransformIdentity, CGFloat(angleInRadians))

通过从this question 获取一些信息,我能够编写 Swift 版本的辅助扩展,但我仍然不知道如何找到 UIImageView 的框架。

extension UIView {
    var originalFrame: CGRect {
        let currentTransform = self.transform
        self.transform = CGAffineTransformIdentity
        let originalFrame = self.frame
        self.transform = currentTransform
        return originalFrame
    }

    var transformedTopLeftPoint: CGPoint {
        return self.transformedPointForOriginalPoint(originalFrame.topLeftPoint)
    }

    var transformedTopRightPoint: CGPoint {
        return self.transformedPointForOriginalPoint(originalFrame.topRightPoint)
    }

    var transformedBottomLeftPoint: CGPoint {
        return self.transformedPointForOriginalPoint(originalFrame.bottomLeftPoint)
    }

    var transformedBottomRightPoint: CGPoint {
        return self.transformedPointForOriginalPoint(originalFrame.bottomRightPoint)
    }

    // helper to get point offset from center
    func centerOffset(point: CGPoint) -> CGPoint {
        return CGPoint(x: point.x - self.center.x, y: point.y - self.center.y)
    }

    // helper to get point back relative to center
    func pointRelativeToCenter(point: CGPoint) -> CGPoint {
        return CGPoint(x: point.x + self.center.x, y: point.y + self.center.y)
    }

    // helper to get point relative to transformed coords
    func transformedPointForOriginalPoint(point: CGPoint) -> CGPoint {
        // get offset from center
        let offset = self.centerOffset(point)
        // get transformed point
        let transformedPoint = CGPointApplyAffineTransform(offset, self.transform)
        // make relative to center
        return self.pointRelativeToCenter(transformedPoint)
    }
}

extension CGRect {
    var topLeftPoint: CGPoint {
        return self.origin
    }

    var topRightPoint: CGPoint {
        return CGPoint(x: self.origin.x + self.size.width, y: self.origin.y)
    }

    var bottomLeftPoint: CGPoint {
        return CGPoint(x: self.origin.x, y: self.origin.y + self.size.height)
    }

    var bottomRightPoint: CGPoint {
        return CGPoint(x: self.origin.x + self.size.width, y: self.origin.y + self.size.height)
    }
}

为了更好地说明,我附上一张图片。

它在其原始框架顶部显示旋转视图(最小的 轮廓)和更新的框架(最大的灰色轮廓)。这 圆圈表示视图的右上角之前和之后 回转。应用变换后,帧更新为 包围视图的最小边界框。它的新起源( 灰色外框的左上角)基本上没有任何关系 与原始视图原点(黑色的左上角 未旋转的内盒)。 iOS 没有提供一种方法来检索它 调整点。以下是执行该操作的一系列视图方法 数学给你。 (上面的 UIView 扩展)

我需要找到灰色框的框架。但即使使用这些方法,我仍然无法弄清楚如何做到这一点。实现我想要的公式/算法是什么?

【问题讨论】:

  • 简单。转换后的视图框架是该视图的边界框。所以只需使用框架。
  • @kirander 但是根据文档,当您将自定义转换设置为 UIView 时,frame 属性变得未定义,根本不应该使用。
  • 是的,确实如此,但提示是变换视图的框架描述了最小边界矩形。为什么不使用这个?

标签: ios swift uiview uiimageview cgaffinetransform


【解决方案1】:

变换后的视图centre 保持不变。因此,您需要根据中心来计算事物。像这样的:

func originalFrame() -> CGRect {
    CGAffineTransform currentTransform = self.transform;
    self.transform = CGAffineTransformIdentity;
    let originalFrame = self.frame;
    self.transform = currentTransform;

    return originalFrame;
}

func centerOffset(point:CGPoint) -> CGPoint {
    return CGPointMake(point.x - self.center.x, point.y - self.center.y);
}

func pointRelativeToCenter(point:CGPoint) -> CGPoint {
    CGPointMake(point.x + self.center.x, point.y + self.center.y);
}


func newPointInView(point:CGPoint) -> CGPoint {
    let offset = self.centerOffset(point)
    let transformedPoint = CGPointApplyAffineTransform(offset, self.transform);
    return self.pointRelativeToCenter(transformedPoint)
}

func newTopLeft() -> CGPoint {
    let frame = self.originalFrame()
    return self.newPointInView(frame)
}

func newTopRight() -> CGPoint {
    let frame = self.originalFrame()
    var point = frame.origin
    point.x = point.x + frame.size.width
    return self.newPointInView(point)
}


func newBottomLeft() -> CGPoint {
    let frame = self.originalFrame()
    var point = frame.origin
    point.y = point.y + frame.size.height
    return self.newPointInView(point)
}


func newBottomRight() -> CGPoint {
    let frame = self.originalFrame()
    var point = frame.origin
    point.x = point.x + frame.size.width
    point.y = point.y + frame.size.height
    return self.newPointInView(point)
}

请参阅此SO Thread 了解更多详情。

【讨论】:

    【解决方案2】:

    提示是变换视图的框架描述了最小边界矩形。你可以使用它。

    // after transform
    // obj-c
    CGRect boundingBoxFrame = myTransformedImageView.frame;
    

    【讨论】:

    • 对不起,还是不明白。您是否建议通过将其边界与其他内容相结合来找到转换后的视图框架?你能提供一个代码示例吗?我度过了一个漫长的夜晚,希望得到更详细的答案。
    • 感谢您的详细回答,它确实有效。但是你能解释一下这种方法的危险吗?根据文档“如果变换属性不是身份变换,则框架属性的值是未定义的,因此应该被忽略。” UIImageView的transform肯定不是CGAffineTransformIdentity,恐怕迟早要另寻出路来计算transform后的view的frame。
    • Frame 属性是计算属性,因此无论何时何地都可以使用。危险是你不应该设置框架属性,只能阅读。
    猜你喜欢
    • 2014-06-20
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2010-10-21
    相关资源
    最近更新 更多