简体   繁体   中英

Pan gesture with boundaries limits & animations

When implementing this code from this answer: https://stackoverflow.com/a/31487087

override func viewDidLoad() {
    super.viewDidLoad()


    var gesture = UIPanGestureRecognizer(target: self, action: Selector("userDragged:"))
    bottomTextField.addGestureRecognizer(gesture)
    bottomTextField.userInteractionEnabled = true
}

func userDragged(gesture: UIPanGestureRecognizer){
    var loc = gesture.locationInView(self.view)
    self.bottomTextField.center = loc

}

The TextField can be dragged around the area. However I want 2 things more. Firstly I want to make boundaries for the are that the TextField can be dragged, so the TextField can not be dragged around the whole view. Secondly it should have a nice animation. For the user experience it cannot just "stop" when the TextField reached his boundaries.

Example: Let's say that the TextField can be dragged around 10% to every direction relative to the roots view. The closer the finger is to the TextField, the more "freedom" the TextField has. When moving the textfield around very close to its original position, the TextField should move more than if the finger is far away from the TextFields originals position. So when the finger goes to the very top right, holding the TextField, (assuming the TextField is centered in the middle) the TextField still respons but it moves very little. When the finger is releasing the TextField, it should bounce back to its original position.

I hope you guys can understand me. If not I can maybe provide another example. Thank you.

Edit:

It is like an pulling an elastic. In the beginning the drag goes smooth, but the more you pulling or dragging around to the boundaries, the TextField IS moving, but very slow. I added an image. Maybe I am making it sound like it is very hard to understand but it really is something simple... Click Here ( Figure 1 is showing that the TextField can go 10 percent each direction. )

Ok, so you want to be using the translation of the gesture recogniser, not the location otherwise you will get a jump if the user doesn't "grab" the view right in the middle:

var startPosition: CGPoint?
func userDragged(gesture: UIPanGestureRecognizer){
    if gesture.state == .began {
        startPosition = bottomTextField.center
    } else if gesture.state == .changed {
        let translation = gesture.translationInView(self.view)
        guard let start = self.startPosition else { return }
        let newCenter = CGPoint(x: start.x + translation.x, y: x.y + translation.y)
        bottomTextField.center = newCenter
    } else {
        startPosition = nil
    }
}

This should fix the first issue, with the view jumping to the finger on gesture start.

Then you're going to want to look closer at let newCenter = CGPoint(x: start.x + translation.x, y: xy + translation.y) to apply some limits to where you can drag the view.

Suppose you don't want the view to be draggable more than 50pts (or 10% of the superview size) in any direction, you can simply use:

let newCenter = CGPoint(x: start.x + min(translation.x, 50), y: x.y + min(translation.y, 50))

Which simply checks which is smaller, the translation or the value 50, and uses the smaller of the two. [Note: this gives you a square limit around the start point, not a radial limit]

And then you want to look at making this a bit more complex, making the altered distance a function of the translation, so that you can taper the movement as it approaches the limit:

let normX = max(min(translation.x / 150, 1), -1)
let deltaX = 50 * sin(normX) // add custom function here
let normY = max(min(translation.y / 150, 1), -1)
let deltaY = 50 * sin(normY) // add custom function here
let newCenter = CGPoint(x: start.x + min(deltaX, 50), y: x.y + min(deltaY, 50))

This is not the transform you will want to use, but indicates how you can achieve an effect of altering the translation to not just linearly move the view, you will want to sub in your own function of translation to produce the deltas based on whatever elastic curve you desire...

(the provided function will normalised the translation between 1 and -1 over a drag distance of 150pts, and then map it over a sine curve to taper off the delta used to move the view, capping the max delta to 50pts.)

If you can better define how you want this curve to work, perhaps I can be of more help?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM