Wingzero
Wingzero

Reputation: 9754

How to filter a quick multiple tap for single Tap event and double tap event

I have below gestures setup:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                            action:@selector(singleTapDetected:)];
singleTap.numberOfTapsRequired = 1;
[self addGestureRecognizer:singleTap];

UITapGestureRecognizer *doubleClick = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                              action:@selector(doubleClickDetected:)];
doubleClick.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleClick];

[singleTap requireGestureRecognizerToFail:doubleClick];

When I quickly tap 3 times, I find that it will be translated into one double tap event and one single tap event, and introduce a bug for my app.

I want something like if user clicks 3 or more times, only a double tap event will be triggered. Could some one help on this? Thank in advance.

Upvotes: 4

Views: 1901

Answers (3)

Surya Kameswara Rao Ravi
Surya Kameswara Rao Ravi

Reputation: 1556

I am answering this for the benefit of iOS 10 and Swift 3 developers.

Currently in iOS 10 with Swift 3 this problem does not exist. A triple tap if not handled is downgraded to double tap and the corresponding action is fired. Try the example below:

Swift 3 Solution:

doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2


singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1

singleTap.require(toFail: doubleTap)

self.view.addGestureRecognizer(doubletap)
self.view.addGestureRecognizer(singleTap)

Upvotes: 6

Wingzero
Wingzero

Reputation: 9754

I created a custom recognizer like below also solved my problem:

@implementation MyTapGestureRecognizer

/**
 *  touchesBegan for custom taps will filter > 2 taps
 *
 *  @param touches touches the recognizer gets
 *  @param event   related event
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    if ([touches count] != 1) {
        return;
    } else {
        UITouch *touch = [touches anyObject];
        if (touch.tapCount >= 3) {
            self.state = UIGestureRecognizerStateFailed;
            return;
        }
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [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];
}

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

@end

Upvotes: 1

user3386109
user3386109

Reputation: 34829

You can use the gesture recognizer's delegate to temporarily disable both gestures after a double click. The code below disables the gestures for 0.6 seconds after a double click.

You'll need a couple properties

@property int disableGestures;
@property CFTimeInterval timeStamp;

and some additional initialization

self.disableGestures = NO;
singleTap.delegate = self;
doubleClick.delegate = self;

and you'll need to conform to the <UIGestureRecognizerDelegate> protocol, and implement the shouldReceiveTouch method

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ( self.disableGestures )
    {
        if ( CACurrentMediaTime() - self.timeStamp < 0.6 )
            return NO;
        self.disableGestures = NO;
    }
    return YES;
}

All that's left is to disable the gestures after a double click

- (void)doubleClickDetected:(UITapGestureRecognizer *)gesture
{
    self.disableGestures = YES;
    self.timeStamp = CACurrentMediaTime();

    // normal processing for the double click goes here
}

Upvotes: 0

Related Questions