UIPanGestureRecognizer limit to coordinates
Asked Answered
S

4

6

I added to my main UIView a subview (called panel) and i added gestureRecognizer to it because i want it to be draggable only for the Y axis and only for certain limits (i.e. 160, 300, over 300 it can't go).

I implemented the gesture handling that way

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
    CGPoint translation = [recognizer translationInView:self.view]; 
    recognizer.view.center = CGPointMake(self.view.frame.size.width/2, recognizer.view.center.y + translation.y);
    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view.superview];

    //now limit the drag to some coordinates
   if (y == 300 || y == 190){
       no more drag
    }
}

but now i don't know how to limit the drag to those coordinates.

It's not a huge view, it's just a small view containing a toolbar and a button.

How can i limit the drag to a coordinate? (x = 160(middle screen), y =404 ) <- example

What should the center be there?

I googled a lot but i didn't find a concrete answer.

Thanks in advance

Stanislaw answered 11/7, 2012 at 20:13 Comment(0)
I
22

First, you need to enforce the limit before you change the view's center. Your code changes the view's center before checking if the new center is out of bounds.

Second, you need to use the correct C operators for testing the Y coordinate. The = operator is assignment. The == operator tests for equality, but you don't want to use that either.

Third, you probably don't want to reset the recognizer's translation if the new center is out-of-bounds. Resetting the translation when the drag goes out of bounds will disconnect the user's finger from the view he's dragging.

You probably want something like this:

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
    CGPoint translation = [recognizer translationInView:self.view];

    // Figure out where the user is trying to drag the view.
    CGPoint newCenter = CGPointMake(self.view.bounds.size.width / 2,
        recognizer.view.center.y + translation.y);

    // See if the new position is in bounds.
    if (newCenter.y >= 160 && newCenter.y <= 300) {
        recognizer.view.center = newCenter;
        [recognizer setTranslation:CGPointZero inView:self.view];
    }
}
Insistency answered 11/7, 2012 at 20:36 Comment(3)
Yes, the operator thing was my fault (maybe for the hurry!). Thanks a lot, it works perfectly!Stanislaw
Rob: Thanks. It worked.Though I am still trying to understand why do you need recognizer setTranslation:CGPointZero in last line. I tried to comment it and the object which is supposed to move goes out of finger tap's area and floats on the screen. Some elaboration would be appreciated.Olgaolguin
By default, the recognizer's translation is how far the touch has moved since the beginning of the touch. But we've already adjusted the position of the view for all of the movement up through the last time the recognizer fired. Resetting the recognizer's translation to zero after each update means that on the next update, the translation will only include the touch's movement since the prior update.Insistency
A
14

There's probably an unintended consequence of Rob's answer. If you drag fast enough the newCenter will be out of bounds but that could happen before the last update. That'll result in the view not being panned all the way to the end. Instead of not updating if the newCenter is out of bounds, you should always update the center but limit the bounds like so:

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
    CGPoint translation = [recognizer translationInView:self.view];

    // Figure out where the user is trying to drag the view.
    CGPoint newCenter = CGPointMake(self.view.bounds.size.width / 2,
    recognizer.view.center.y + translation.y);

    // limit the bounds but always update the center
    newCenter.y = MAX(160, newCenter.y);
    newCenter.y = MIN(300, newCenter.y);

    recognizer.view.center = newCenter;
    [recognizer setTranslation:CGPointZero inView:self.view];
}
Assets answered 8/1, 2015 at 22:32 Comment(1)
thumbs up to this answer, I find it very much better than the one accepted as an answer!Shuttle
E
1

Above both answers are correct for Y coordinate. This is for whom who are looking for both X & Y coordinates. Just done small changes.

- (void)panWasRecognized:(UIPanGestureRecognizer *)panner {
    UIView *piece = [panner view];
    CGPoint translation = [panner translationInView:[piece superview]];

    CGPoint newCenter = CGPointMake(panner.view.center.x + translation.x,
                                    panner.view.center.y + translation.y);
    if (newCenter.y >= 0 && newCenter.y <= 300 && newCenter.x >= 0 && newCenter.x <=300) 
    {
        panner.view.center = newCenter;
        [panner setTranslation:CGPointZero inView:[piece superview]];
    }
}
Encephalograph answered 20/7, 2017 at 8:47 Comment(0)
B
0
-(void)handlePan:(UIPanGestureRecognizer*)pgr;
{
    if (pgr.state == UIGestureRecognizerStateChanged) {
        CGPoint center = pgr.view.center;
        CGPoint translation = [pgr translationInView:pgr.view];
        center = CGPointMake(center.x + translation.x,
                             center.y + translation.y);

        if ([self pointInside:center withEvent:nil])
        {
            pgr.view.center = center;
            [pgr setTranslation:CGPointZero inView:pgr.view];
        }
    }
}
Become answered 22/8, 2019 at 0:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.