Search code examples
swiftiphoneuipangesturerecognizer

How do I set limits in the y-axis for a Pan Gesture?


I want to limit my imageview to specific y-coordinates, but every-time I drag it over or below the 2-coordinates, the view gets stuck and doesn't move again. Also, if I drag fast enough, the imageView goes above or below the coordinates that i limited it to.

@IBAction func handlePan(_ gesture: UIPanGestureRecognizer) {
      // 1
      let translation = gesture.translation(in: view)

      // 2
      guard let gestureView = gesture.view else {
        return
      }
        
        if gestureView.center.y >= 161 && gestureView.center.y <= 561 {
            gestureView.center.y = gestureView.center.y + translation.y
            gesture.setTranslation(.zero, in: view)
        }
        
      // 3
      gesture.setTranslation(.zero, in: view)
    }

Solution

  • Instead of just not moving the image view at all when its y coordinate is outside of the specified range, you should still allow the image view to be moved downwards if it is too high, and upwards if it is too low.

    It would be easier to specify in which situations you don't want the image view to be moved:

    • y < 161 and panning upwards
    • y > 561 and panning downwards

    Also, the reason why you can move it out of the valid y range by dragging very fast is because you only check whether the image view's y coordinate is in the range before moving it, but not after. You should instead clamp the values when adding translation.y.

    @IBAction func handlePan(_ gesture: UIPanGestureRecognizer) {
        // 1
        let translation = gesture.translation(in: view)
    
        // 2
        guard let gestureView = gesture.view else {
            return
        }
    
        // in these two cases, don't translate the image view
        if (gestureView.center.y < 161 && translation.y < 0) ||
            (gestureView.center.y > 561 && translation.y > 0) {
            gesture.setTranslation(.zero, in: view)
            return
        }
    
        // clamping the translated y 
        gestureView.center.y = min(max(gestureView.center.y + translation.y, 161), 561)
        gesture.setTranslation(.zero, in: view)
    }