iOS Swift:无需调整大小即可旋转和缩放 UIView

Posted

技术标签:

【中文标题】iOS Swift:无需调整大小即可旋转和缩放 UIView【英文标题】:iOS Swift: Rotate and Scale UIView without resizing 【发布时间】:2019-01-04 15:21:25 【问题描述】:

我有一个 UIView,我想通过平移和捏合手势进行缩放和旋转。但问题是当我缩放视图时,然后当我旋转它时,它会在缩放之前调整回初始值。

extension UIView 

    func addPinchGesture() 
        var pinchGesture = UIPinchGestureRecognizer()
        pinchGesture = UIPinchGestureRecognizer(target: self,
                                                action: #selector(handlePinchGesture(_:)))
        self.addGestureRecognizer(pinchGesture)
    

    @objc func handlePinchGesture(_ sender: UIPinchGestureRecognizer) 
        self.transform = self.transform.scaledBy(x: sender.scale, y: sender.scale)
        sender.scale = 1
    



// ROTATION
extension UIView 

    func addRotationGesture() 
        var rotationGesture = RotationGestureRecognizer()
        rotationGesture = RotationGestureRecognizer(target: self,
                                                    action: #selector(handleRotationGesture(_:)))
        self.addGestureRecognizer(rotationGesture)
    

    @objc func handleRotationGesture(_ sender: RotationGestureRecognizer) 
        var originalRotation = CGFloat()
        switch sender.state 
        case .began:
            sender.rotation = sender.lastRotation
            originalRotation = sender.rotation
        case .changed:
            let newRotation = sender.rotation + originalRotation
            self.transform = CGAffineTransform(rotationAngle: newRotation) // Rotation is fine but it is resizing view
//            self.transform = self.transform.rotated(by: newRotation / CGFloat(180 * Double.pi)) // NOT WORKING i.e. irregular rotation
        case .ended:
            sender.lastRotation = sender.rotation
        default:
            break
        
    


缩放前

缩放后

旋转后

我希望它在不影响视图大小的情况下旋转。我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

您在应用旋转变换时正在重置视图的比例变换。创建一个属性来保持视图的原始比例。

var currentScale: CGFloat = 0

当捏合完成时,将 currentScale 值存储到当前比例。然后在旋转时也使用这个比例,然后再应用旋转。

let scaleTransform = CGAffineTransform(scaleX: currentScale, y: currentScale)

let concatenatedTransform = scaleTransform.rotated(by: newRotation)
self.transform = concatenatedTransform

您正在使用扩展来添加手势识别器,因此您无法存储 currentScale。您还可以从当前变换值中获取视图的比例值。这是您的代码的样子,

extension UIView 

    var currentScale: CGPoint 
        let a = transform.a
        let b = transform.b
        let c = transform.c
        let d = transform.d

        let sx = sqrt(a * a + b * b)
        let sy = sqrt(c * c + d * d)

        return CGPoint(x: sx, y: sy)
    


    func addPinchGesture() 
        var pinchGesture = UIPinchGestureRecognizer()
        pinchGesture = UIPinchGestureRecognizer(target: self,
                                                action: #selector(handlePinchGesture(_:)))
        self.addGestureRecognizer(pinchGesture)
    

    @objc func handlePinchGesture(_ sender: UIPinchGestureRecognizer) 
        self.transform = self.transform.scaledBy(x: sender.scale, y: sender.scale)
        sender.scale = 1
    



// ROTATION
extension UIView 

    func addRotationGesture() 
        var rotationGesture = RotationGestureRecognizer()
        rotationGesture = RotationGestureRecognizer(target: self,
                                                    action: #selector(handleRotationGesture(_:)))
        self.addGestureRecognizer(rotationGesture)
    

    @objc func handleRotationGesture(_ sender: RotationGestureRecognizer) 
        var originalRotation = CGFloat()
        switch sender.state 
        case .began:
            sender.rotation = sender.lastRotation
            originalRotation = sender.rotation
        case .changed:
            let scale = CGAffineTransform(scaleX: currentScale.x, y: currentScale.y)
            let newRotation = sender.rotation + originalRotation

            self.transform = scale.rotated(by: newRotation)
        case .ended:
            sender.lastRotation = sender.rotation
        default:
            break
        
    

我使用这个answer作为提取比例值的参考。

【讨论】:

它可以工作,但为什么它不能通过let newRotation = sender.rotation + originalRotation self.transform = self.transform.rotated(by: newRotation) 工作?? @AbhishekThapliyal 如果您不重置视图转换,那应该确实有效。 你能帮帮我吗,检查第一个答案中的 cmets ??? ***.com/questions/62372147/…【参考方案2】:

我遇到了同样的问题一旦我用手指捏住,然后从按钮旋转后,它会自动从当前缩小,但我在下面设置了逻辑。

 @objc func rotateViewPanGesture(_ recognizer: UIPanGestureRecognizer) 
            touchLocation = recognizer.location(in: superview)
            let center = CGRectGetCenter(frame)

            switch recognizer.state 
            case .began:
                deltaAngle = atan2(touchLocation!.y - center.y, touchLocation!.x - center.x) - CGAffineTrasformGetAngle(transform)
                initialBounds = bounds
                initialDistance = CGpointGetDistance(center, point2: touchLocation!)

            case .changed:

                let ang = atan2(touchLocation!.y - center.y, touchLocation!.x - center.x)
                let angleDiff = deltaAngle! - ang

                let a = transform.a
                let b = transform.b
                let c = transform.c
                let d = transform.d

                let sx = sqrt(a * a + b * b)
                let sy = sqrt(c * c + d * d)

                let currentScale = CGPoint(x: sx, y: sy)
                let scale = CGAffineTransform(scaleX: currentScale.x, y: currentScale.y)
                self.transform = scale.rotated(by: -angleDiff)

                layoutIfNeeded()
            case .ended:

              print("end gesture status")
            default:break

            
        

【讨论】:

以上是关于iOS Swift:无需调整大小即可旋转和缩放 UIView的主要内容,如果未能解决你的问题,请参考以下文章

响应浏览器窗口 (CSS) 调整、缩放和居中图像

在图像移动/调整大小/旋转操作中在图像周围放置一些指示符

使 UIImageView 及其 UIImage 按比例缩放而无需额外的填充

UICollectionView - 在设备旋转上调整单元格大小 - Swift

在 Swift 4 中自动调整缩放以适应 iOS 中的所有标记

如何通过平移、旋转和/或缩放调整来匹配两个分割蒙版