Search code examples
swiftrotationgesturepi

Swift - Rotate gesture and rotation increments of 90 degrees


I have a rotateView setup with a UIRotationGestureRecognizer. Works as intended, however I would like to only rotate in notches/increments of 90 degrees. The default behavior allows you to be very granular and precise with the rotation. I want it to be the opposite, of only 4 possible positions.

The code I have below is as close I could get, however the problem I am facing is the rotation only happens once, and only to one direction (rotates to the right, even if I 2-fingers rotate to the left).

My code

func rotatedView(recognizer:UIRotationGestureRecognizer){
    let pi = CGFloat(M_PI)
    rotateView.transform = CGAffineTransformMakeRotation(pi/2)
    recognizer.rotation = 0
    if recognizer.state == UIGestureRecognizerState.Changed {
        print("rotation began")
    }
    else {
        print("rotation ended")
    }
}

How can I modify the above code to allow for 90 degree rotation increments in either direction based on gesture?


Solution

  • I achieved this by implementing it as follows:

    @IBAction func handleRotation(_ recognizer: UIRotationGestureRecognizer) {
        if let recognizerView = recognizer.view {
            recognizerView.transform = recognizerView.transform.rotated(by: recognizer.rotation)
            recognizer.rotation = 0
    
            let radians:Double = atan2( Double(recognizerView.transform.b), Double(recognizerView.transform.a))
            let degrees = radians * Double((180 / Float.pi))
    
            if recognizer.state == .ended || recognizer.state == .cancelled {
                var degreeToAnimate:CGFloat = 0
    
                switch degrees {
                case -45...45:
                    print("the default value 0, no need to any assign...")
                case 46...135:
                    degreeToAnimate = CGFloat(M_PI_2)
                case 136...180, -180 ... -136:
                    degreeToAnimate = CGFloat(M_PI)
                case -135 ... -46:
                    degreeToAnimate = CGFloat(-M_PI_2)
                default:
                    print("!")
                }
    
                UIView.animate(withDuration: 0.3, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 1.0, options: .curveEaseIn, animations: {
                    recognizerView.transform = CGAffineTransform(rotationAngle: degreeToAnimate)
                }, completion: { _ in
                    recognizer.rotation = 0
                })
            }
        }
    }
    

    Note that I added the UIRotationGestureRecognizer on the desired view from the Interface Builder, that's why the function is an @IBAction.

    Output:

    enter image description here