View panning beyond limit

Viewed 33

I have two UiViews: skinView (purple) and bottomView (pink). SkinView is above bottomView. Both views are the same size and have the same constraints. skinView has a pan gesture recognizer that only drags up and down by adjusting the center Y constraint. The view will only pan up half way and back down. I added some logic to only pan down while the skinView y origin is less than the bottom view y origin. However, it seems like it drags further down than the bottom view y origin sometimes.

Added some logs and I see the Y origin of the skinView can be off by quite a bit once the pan down is complete:

Skin View y position: 77.0

Bottom View y position: 1.6666666666666856

override func viewDidLoad() {
    super.viewDidLoad()
    panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPan(_:)))
    skinView.addGestureRecognizer(panGestureRecognizer!)
}

@objc private func didPan(_ sender: UIPanGestureRecognizer) {
    let height = self.skinView.frame.size.height/2
    let skinViewBottomY = self.skinView.frame.origin.y + self.skinView.frame.size.height
    let bottomViewBottomY = self.bottomView.frame.origin.y + self.bottomView.frame.size.height
    

    if panGestureRecognizer!.state == .began {
        print("Pan started")
     } else if panGestureRecognizer!.state == .changed {
         let translation = panGestureRecognizer!.translation(in: self.skinView)
         if (translation.y < 0 && skinViewBottomY >= bottomViewBottomY/2) {
             self.verticalConstraint?.constant += translation.y
             panGestureRecognizer!.setTranslation(.zero, in: self.skinView)
             print("UP")
         } else if (translation.y > 0 && self.skinView.frame.origin.y < self.bottomView.frame.origin.y) {
             self.verticalConstraint?.constant += translation.y
             panGestureRecognizer!.setTranslation(.zero, in: self.skinView)
             print("DOWN")
         }
     }
}

enter image description here

skinView

skinViewUp

skinViewDown

1 Answers

If I understand correctly...

You want to allow the purple "skinView" to be dragged UP, but only as far as half-way... and dragged DOWN, but only as far as half-way.

So, when pan state is .changed, you want to:

  • get the y translation
  • add it to the current vertical constraint constant
  • allow it to be a maximum of 1/2 height
  • then, allow it to be a minimum of minus 1/2 height

So, you can simplify your code block like this:

@objc private func didPan(_ sender: UIPanGestureRecognizer) {

    let halfHeight = self.skinView.frame.size.height/2
    
    if sender.state == .began {

        print("Pan started")

    } else if sender.state == .changed {

        let translation = sender.translation(in: self.skinView)
        // current verticalConstraint constant
        let curY = self.verticalConstraint.constant
        // maximum possible new value is halfHeight
        let maxYval = min(curY + translation.y, halfHeight)
        // minimum possible new value is -halfHeight
        let newYval = max(maxYval, -halfHeight)
        // update the constraint constant
        self.verticalConstraint.constant = newYval
        // reset pan translation
        sender.setTranslation(.zero, in: self.skinView)

    }

}

Edit - in response to comment...

If you want to restrict the drag to only UP, change this line:

let maxYval = min(curY + translation.y, halfHeight)

to this:

let maxYval = min(curY + translation.y, 0.0)

So our code is now saying "don't let the centerY constraint constant become greater than Zero".

We can now drag the "skinView" UP half-way, but can only drag DOWN to its original position.

Related