Search code examples
iosiphoneswiftxcodeuipangesturerecognizer

(Swift) UIPanGestureRecognizer works fine on view until subview is added to it


I have the following view (which is a subview of the overall view controller):

lazy var superView: UIView = {
    let cv = UIView()

    cv.backgroundColor = .gray
    cv.translatesAutoresizingMaskIntoConstraints = false
    cv.layer.cornerRadius = 5     
    cv.layer.masksToBounds = true     
    cv.isUserInteractionEnabled = true
    cv.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan)))

    return cv
}()

and here is where I set my constraints for it:

// constraints for super view
func setupSuperView() {
    superView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    superView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

    superView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
    superView.heightAnchor.constraint(equalTo: view.heightAnchor, constant: -200).isActive = true

    // ISSUE: For some reason, adding this subview with or without constraints screws up the pan functionality of the superview
    superView.addSubview(subView)
}

this is the subview I add to be inside of the superView (which I am treating as a container view):

lazy var subview: UIImageView = {
    let sv = UIImageView()

    sv.translatesAutoresizingMaskIntoConstraints = false
    sv.contentMode = .scaleAspectFill        

    return sv
}()

And its constraints:

// constraints for yes/no view within superview
func setupSubView() {
    subView.centerXAnchor.constraint(equalTo: superView.centerXAnchor).isActive = true
    subView.centerYAnchor.constraint(equalTo: superView.centerYAnchor).isActive = true
}

Finally, here is where I establish the functionality for the pan gesture:

 // pan functionality for swiping on superview
func handlePan(gesture: UIPanGestureRecognizer) {

    guard let superview = gesture.view else {
        return
    }

    // point you are tapped on
    let point = gesture.translation(in: view)

    // reference for how far left or right of the center of the superview your pan is
    let xFromCenter = superview.center.x - view.center.x

    // allows the superview to move with your finger
    superview.center = CGPoint(x: view.center.x + point.x, y: view.center.y + point.y)

    // dragged right
    if xFromCenter > 0 {
        subView.image = #imageLiteral(resourceName: "yes")
        subView.tintColor = UIColor.green

    // else dragged left
    } else {
        subView.image = #imageLiteral(resourceName: "no")
        subView.tintColor = UIColor.red
    }

    // when you let go
    if gesture.state == UIGestureRecognizerState.ended {
        // animate superview back to center where it originally was
        UIView.animate(withDuration: 0.2) {

            superview.center = self.view.center
        }
    }

}

Before I added the subview (and when I comment it out) the pan gesture works perfectly fine on the superview. However, when I constrain the subview to be in the center of the superview and try moving the superview around the view controller, it acts bizarrely (only moving to the left properly, constantly jerking back to the center when moving to the right).

Any and all help is greatly appreciated.


Solution

  • I figured out the issue. While I don't know the reason why this is the fix, the issue lies in the fact that the image I was using for the "no" option of panning the container view left was causing the entire view to act bizarrely because it is a different image.

    I tested this out by making both options "yes" despite whether you pan the view left or right. This fixed the issue which led me to believe that the problem was the image being switched depending on whether you swipe left or right. I don't know why it has an issue with displaying two different images but I will try to figure that out as well.

    Thank you for all of the helpful input!