Question

I have a view with four pan gestures attached. The first has both max and min number of touches set to 1, the second to 2, etc. This makes it so each will only recognize one touch while up to four fingers slide around on the screen.

That's working dandy. What isn't working is detecting when individual touches end. Anything I have set to happen when a gesture ends only happens when all gestures have ended completely.

Example delegate method:

- (void) handlePan:(UIPanGestureRecognizer*)recognizer {

    //Setting what happens when a gesture is recognized as beginning
    if (recognizer.state == UIGestureRecognizerStateBegan) {

    //...whatever happens, bunnies follow your finger or whatever

    } else

    //Setting what happens when a gesture ends
    if ((recognizer.state == UIGestureRecognizerStateEnded) | 
        (recognizer.state == UIGestureRecognizerStateCancelled) |
        (recognizer.state == UIGestureRecognizerStateFailed)) {

        NSLog(@"end");

    }
}

What should be happening is that I see "end" in the console whenever any finger is lifted. Instead, I see nothing until all fingers are lifted, at which point I see "end" repeated four times (or as many times as fingers that were on the screen).

Is there any way I can make this work the way I intend?

edit After fiddling I see that I may not be analyzing my problem correctly. The whole reason I want to detect when a gesture's touch ends is that I want to have gestures able to become active when there is more than one touch on screen, but I want each gesture to only track one touch itself. I was setting an "active" flag on gestures that were tracking touches, and then toggling that flag off after touches ended, and that wasn't working, because touch-end-detection was hard to implement well.

But if there's a different way to achieve the same thing, that's the real thing I'm looking for: among many overlapping touches, have each gesture recognizer track one and only one.

Was it helpful?

Solution 2

This is what eventually worked.

In short, I made a flag that flipped whenever a gesture recognizer was assigned a touch, ensuring no other recognizers accepted that touch. I also tested each recognizer to make sure it only accepted a touch when it wasn't already following a touch. So I made each touch only get assigned once, and each recognizer only accept one touch. Worked like a charm.

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
            //set this to no every time a new touch happens, meaning it isn't taken yet.
            touchTaken = NO;
        }

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

        //If the touch is taken or the gesture's already following a touch, say no.
        if (touchTaken | ([gestureRecognizer numberOfTouches] > 0)) {
            return NO;
        }
        else {
            touchTaken = YES;
            return YES;
        }
    }

OTHER TIPS

You may want to do something like - it catches the change in fingers on the screen for the given gesture; you may need to add some more logic surrounding which gesture you're working with:

switch( recognizer.numberOfTouches ) {
     case 1: {
         NSLog(@"1 ");
         break;
     }
     case 2: {
         NSLog(@"2");
         break;
     }
     case 3: {
          NSLog(@"3");
          break;
     }
     case 4: {
          NSLog(@"4");
          break;
     }
     default: {
          NSLog(@"0");
     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top