Theo Strauss
Theo Strauss

Reputation: 1351

Rotating ImageView using UIPanGestureRecognizer- Swift 3

I am trying to rotate an ImageView I have depending on the X coordinate it is on. Basically, I want it to have a rotation of 0º when x = 300 and a rotation of 180º when x = 190.

I had to program the UIPanGestureRecognizer programmatically. Here is the code I currently have right now:

    @objc func personDrag(recognizer: UIPanGestureRecognizer) {

    let rotationSub: CGFloat = 1

    let translation = recognizer.translation(in: rView)
    if let view = recognizer.view {
        view.center = CGPoint(x:view.center.x +  translation.x, y:view.center.y + translation.y)
        view.transform = view.transform.rotated(by: CGFloat.pi - rotationSub)
    }
    recognizer.setTranslation(CGPoint.zero, in: rView)

}

I was going to attempt to change the rotation degree by 1 every time they panned but it doesn't really work/make sense. Any help would be appreciated. Thank you so much!

Cheers, Theo

Upvotes: 3

Views: 2306

Answers (3)

Mindset
Mindset

Reputation: 1

Using Swift5

Programmatically

Rotate view by single point touch

import UIKit

class ViewController: UIViewController {
    
    //Variable for rotating
    private var deltaAngle:CGFloat = 0
    
    let squareView : UIView = {
        let anyView = UIView()
        anyView.backgroundColor = .red
        anyView.isUserInteractionEnabled = true
        anyView.isMultipleTouchEnabled = true
        return anyView
        
    }()
    
    let rotateButton : UIButton = {
        let button = UIButton()
        button.backgroundColor = .black
        button.setImage(UIImage(systemName: "rotate.right"), for: .normal)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        squareView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        rotateButton.frame = CGRect(x: 0, y: squareView.frame.height-30, width: 30, height: 30)
        squareView.center = view.center
        view.addSubview(squareView)
        squareView.addSubview(rotateButton)
        
        let PanToRotate = UIPanGestureRecognizer(target: self, action: #selector(handleRotateGesture(_:)))
        rotateButton.addGestureRecognizer(PanToRotate)
        
    }
    
    
    
    
    @objc func handleRotateGesture(_ recognizer : UIPanGestureRecognizer){
        let touchLocation = recognizer.location(in: squareView.superview)
        
        let center = squareView.center
        
        switch recognizer.state{
            
        case .began :
            self.deltaAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) - atan2(squareView.transform.b, squareView.transform.a)
            
        case .changed:
            let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x)
            
            let angleDiff = self.deltaAngle - angle
            
            squareView.transform = CGAffineTransform(rotationAngle: -angleDiff)
                        
        default: break
            
        }
        
    }
    
}

Upvotes: 0

kalpesh
kalpesh

Reputation: 1287

I hope this will help you.

 @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

            }
        }

Upvotes: 0

Oleh Zayats
Oleh Zayats

Reputation: 2443

You can build your implementation on this:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageview: UIImageView!

    private var currentRotation: Rotation = .none

    /* Certain rotation points (rotation of 0º when x = 300 and a rotation of 180º when x = 190) */
    enum Rotation {
        case none, xPoint190, xPoint300
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        imageview.addGestureRecognizer(gestureRecognizer)
        imageview.isUserInteractionEnabled = true
    }

    @IBAction func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
        guard gestureRecognizer.state == .began || gestureRecognizer.state == .changed else {
            return
        }

        guard let imgView = gestureRecognizer.view else {
            return
        }

        let translation = gestureRecognizer.translation(in: self.view)
        imgView.center = CGPoint(x: imgView.center.x + translation.x, y: imgView.center.y + translation.y)
        gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)

        let angle: CGFloat = self.degreesToRadians(180.0)

        /* After reaching x point case - rotating and setting rotation occured to prohibit further rotation */

        if imgView.layer.frame.origin.x <= 190, currentRotation != .xPoint190 {

        imgView.transform = imgView.transform.rotated(by: angle)
        currentRotation = .xPoint190

    } else if imgView.layer.frame.origin.x >= 300, currentRotation != .xPoint300 {

        imgView.transform = imgView.transform.rotated(by: angle)
        currentRotation = .xPoint300
    }


    private func degreesToRadians(_ deg: CGFloat) -> CGFloat {
        return deg * CGFloat.pi / 180
    }
}

Upvotes: 4

Related Questions