Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is there a delay when moving object using UIPanGestureRecognizer

I'm moving UIView object using UIPanGestureRecognizer — how much I drag my finger on screen, that much I move the view in the same direction (only in X - left or right, Y is not changing). It works fine, but with (very noticeable) delay.

Here is the method that handles the UIPanGestureRecognizer event:

-(void)movePages:(UIPanGestureRecognizer *)sender
{
    if (switchingMode == 1) {
        if ([sender state] == UIGestureRecognizerStateBegan) {
            fingerStartPosition = [sender locationInView:self.view].x;
            viewStartPosition = [[viewControllers objectAtIndex:activeViewControllerIndex] view].center;
        }
        [[[[viewControllers objectAtIndex:activeViewControllerIndex] view] layer] setPosition:CGPointMake(viewStartPosition.x - (fingerStartPosition - [sender locationInView:self.view].x) , viewStartPosition.y)];            
    }
}

I've tried to set position of the view using its layer, I've also tried setting the frame, using animations with different durations, but everything behaved the same. Any idea why this delay occurs ?

like image 632
Michael Avatar asked May 23 '12 21:05

Michael


3 Answers

Use a UILongPressGestureRecognizer and set the minimumPressDuration to 0.0. This recognizes instantly and you get all the same updates including the UIGestureRecognizerStateChanged with the updated location.

like image 136
Derrick Hathaway Avatar answered Nov 11 '22 18:11

Derrick Hathaway


I found that it was faster responding if you use just regular touchesBegan, Moved and Ended. I even subclassed a UIGestureRecognizer, and it still had lag on the panning gesture. Even though the touchesBegan within the UIGestureRecognizer would trigger on time, the state change would take a half second to change its state... It seems faster to just use a plain old TouchesBegan, especially if you're cpu is doing a lot.

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
    if touches.count == 1
    {
        initialTouchLocation = (touches.first?.locationInView(self).x)!
    }
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
{
    if touches.count == 1
    {
        let locationInView = touches.first?.locationInView(self)
        if !thresholdHit
        {
            //this is the threshold for x movement in order to trigger the panning...
            if abs(initialTouchLocation - locationInView!.x) > 1
            {
                thresholdHit = true
            }
        }
        else
        {
            if (self.frame.width != CGFloat(screenSize))
            {
                let panDelta = initialTouchLocation - locationInView!.x
            }
        }
    }
}
like image 37
KorinW Avatar answered Nov 11 '22 16:11

KorinW


The GestureRecognizer can't be sure, if it is a pan gesture, before you moved your finger some pixels. I don't know the exact tolerance value, but that is why you feel a delay.

Documentation:

A panning gesture is continuous. It begins when the minimum number of fingers allowed have moved enough to be considered a pan.

If you want instant movement, you probably need to build your own logic using touchesMoved:.

Another approach could be, to animate to the first recognized point. But that doesn't remove the delay. For that approach you could have a look at my JDDroppableView on github.

like image 3
calimarkus Avatar answered Nov 11 '22 18:11

calimarkus