6
votes

I'm having some issues trying to implement a 3 finger pinch.

I've been using a 2 finger pinch with a 2 finger rotation, individually ! (no simultaneous gesture needed or wanted) the problem is that many times, the system identify the wrong movement because both of them are very similar, so I end up having to remove my fingers and press again in order to try to make the system identify the rotation (usually it identifies the pinch first)

I searched a lot to see if the delayBegin would help, or if I could do something activating the simultaneous gesture, but none worked ok, so my idea was to instead of using 2 fingers to pinch, I could use 3 (since it's easier to pinch than rotate).

The problem is, as you know, Pinch only works with 2 fingers. So I decided I could subclass the UIPinchGestureReconizer and only allow it to work when there is 3 fingers on screen. The rest it could work as the standard pinch works, even ignoring the third finger (to calculate the scale) but being sure the third finger still on screen.

So I tried the following implementation for my ThreeFingerPinchRecognizer (that Sub classes the UIPinchGestureRecognizer )

@implementation GRThreeFingerPinchRecognizer

-(id)initWithTarget:(id)target action:(SEL)action
    {
    self = [super initWithTarget:target action:action];
    if(self){
    }
    return self;
}

- (void)reset
{
    [super reset];
}

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    int numberOfTouches = event.allTouches.count;
    if (numberOfTouches == 3) 
     {
        [super touchesBegan:touches withEvent:event];
     }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    int numberOfTouches = event.allTouches.count;
    if (numberOfTouches == 3)
    {
        [super touchesMoved:touches withEvent:event];
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{ 
        [super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
 }

So, as you can see, I'm trying to get the same functionality of the 2 finger pinch (by only calling the [super] functions, and at the touchesBegan and touchesMoved functions, I'm testing if there is 3 fingers on screen (by looking at the event.alltouches.count)

With this, the rotation is working perfect with the two fingers, but the pinch is not working very well, its hard to activate it and when it does, it does not work as the two finger pinch...

I know I may be doing this totally wrong, so any help will be great !!

Thank you very much!

1
Intersting approach, but the PinchGestureRecognizer (which in the end you are invoking) probably is expecting 2 touches not 3, I would perhaps try to remove one of the touches before you call super..you are going to have to figure out which one to remove though.. - Daniel
I believed that that is handled inside the PinchGesture, since I'm not changing anything in the event being passed, Im only forwarding it! if I remove the "if", pinch works correctly (but with 2 fingers) - Plauto Abreu
*A good note: 3 finger features will not work on users devices that have zoom enabled in settings (an Apple feature where you double tap the screen with 3 fingers to zoom in (in any app, much like how the screenshot feature works in any app))... Using a 3 finer detecting for app capability could be as deadly as using a home-button detection feature. (I, along with many others have this zoom feature enabled) - Albert Renshaw
Why don't you create your own subclass of UIGestureRecognizer and actually check the movement of the 2 fingers, and then select accordingly the gesture? As the fingers move, a pinch should keep the touches within the segment of the original 2 points, or close to it. On the other hand, the rotation should move them significantly away. - Rikkles
Could you not leave the pinch for two fingers and use a single finger move for the rotation? - ader

1 Answers

0
votes

See this Snippet can help u identify the State of pinch:

if (pinch.numberOfTouches > 1)
{
    CGPoint firstPoint = [pinch locationOfTouch:0 inView:self];
    CGPoint secPoint = [pinch locationOfTouch:1 inView:self];
    currentUpperY = MIN(firstPoint.y, secPoint.y);
    if (previousY == 0) previousY = currentUpperY;
    Float32 y = (self.contentOffset.y + previousY - currentUpperY);
    [self setContentOffset:CGPointMake(0, y < 0 ? 0 : y) animated:NO];

    if (pinch.state == UIGestureRecognizerStateBegan)
    {
        pinchStarted = YES;
        firstY = MIN(firstPoint.y, secPoint.y);
        secondY = MAX(firstPoint.y, secPoint.y);
        NSArray *pinchedIndexs = [self indexPathsForRowsInRect:CGRectMake(0.0, firstY, CGRectGetWidth(self.bounds), secondY)];
        if (pinchedIndexs.count) itemToOpenOrClose = [[currentItems subarrayWithRange:NSMakeRange(((NSIndexPath *)[pinchedIndexs objectAtIndex:0]).row, pinchedIndexs.count - 1)] copy];
    }
}

if ((pinch.state == UIGestureRecognizerStateChanged && pinchStarted && itemToOpenOrClose.count)
    || pinch.state == UIGestureRecognizerStateEnded)
{
    if (pinch.scale > 1) // Pinch OUT
    {
        for (Item *item in itemToOpenOrClose)
        {                
            [self openItem:item inIndexPath:[NSIndexPath indexPathForRow:[currentItems indexOfObject:item] inSection:0]];
        }
    }
    else if (pinch.scale < 1) // Pinch IN
    {
        for (Item *item in itemToOpenOrClose)
        {
            [self closeItem:item inIndexPath:[NSIndexPath indexPathForRow:[currentItems indexOfObject:item] inSection:0]];
        }
    }

    if (pinch.state == UIGestureRecognizerStateEnded)
    {
        pinchStarted = NO;
        itemToOpenOrClose = nil;
        previousY = 0;
    }
}