Search code examples
swiftuiimageviewcgaffinetransformuiswipegesturerecognizer

UIImageView transform loses swipe gesture


I have an image that I want to rotate every time the user swipes on it. It works the first time, and first time only! How is it that the view is losing the swipe gesture recognizer?

        myCircle = UIImageView( ... )
        myCircle.isUserInteractionEnabled = true

        let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
        swipeLeft.direction = .left
        myCircle.addGestureRecognizer(swipeLeft)
        let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
        swipeRight.direction = .right
        myCircle.addGestureRecognizer(swipeRight)
    }

    @objc func swiping(sender: UISwipeGestureRecognizer) {
        // this function only called the first time!
        if sender.direction == UISwipeGestureRecognizer.Direction.left {
            myCircleRotation -= CGFloat(Double.pi/2)
        } else if sender.direction == UISwipeGestureRecognizer.Direction.right {
            myCircleRotation += CGFloat(Double.pi/2)
        }
        // if I comment out this next line, function is called (correctly) every swipe!
        myCircle.transform = CGAffineTransform(rotationAngle: myCircleRotation)
    }

Solution

  • You can add a UIView as a container view to your hierarchy, and then add the UIGestureRecognizers to the container view instead of to the UIImageView. This would allow your image to be rotated without impact to the gestures.

    import UIKit
    
    class ImageViewController: UIViewController {
    
        @IBOutlet weak var myCircleView: UIImageView!
        @IBOutlet weak var containerView: UIView!
    
        var myCircleRotation:CGFloat = 0
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupImage()
        }
    
        private func setupImage() {
            let image = UIImage(named: "your-image")
            myCircleView.image = image
            myCircleView.isUserInteractionEnabled = true
    
            let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
            swipeLeft.direction = .left
            containerView.addGestureRecognizer(swipeLeft)
            let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
            swipeRight.direction = .right
            containerView.addGestureRecognizer(swipeRight)
        }
    
        @objc func swiping(sender: UISwipeGestureRecognizer) {
            // this function only called the first time!
            if sender.direction == UISwipeGestureRecognizer.Direction.left {
                myCircleRotation -= CGFloat(Double.pi/2)
            } else if sender.direction == UISwipeGestureRecognizer.Direction.right {
                myCircleRotation += CGFloat(Double.pi/2)
            }
    
            UIView.animate(withDuration: 0.5) {
                self.myCircleView.transform = CGAffineTransform(rotationAngle: self.myCircleRotation)
            }
        }
    }