How to recognize oneTap/doubleTap at moment?

前端 未结 7 735
独厮守ぢ
独厮守ぢ 2020-12-05 05:51

I Know filtering oneTap/doubleTap using a Apple API. code are follows.

UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
          


        
相关标签:
7条回答
  • 2020-12-05 06:39

    The easiest way to do this is to subclass UITapGestureRecognizer and not a general UIGestureRecognizer.

    Like this:

    #import <UIKit/UIGestureRecognizerSubclass.h>
    
    #define UISHORT_TAP_MAX_DELAY 0.2
    @interface UIShortTapGestureRecognizer : UITapGestureRecognizer
    
    @end
    

    And simply implement:

    @implementation UIShortTapGestureRecognizer
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [super touchesBegan:touches withEvent:event];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(UISHORT_TAP_MAX_DELAY * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
        {
            // Enough time has passed and the gesture was not recognized -> It has failed.
            if  (self.state != UIGestureRecognizerStateRecognized)
            {
                self.state = UIGestureRecognizerStateFailed;
            }
        });
    }
    @end
    
    0 讨论(0)
  • 2020-12-05 06:39
    @interface NaMeClass ()
    
    @property (nonatomic, strong) UITapGestureRecognizer * singleTap;
    @property (nonatomic, strong) NSTimer *timer;
    
    @end
    

    //...code...

    //viewDidLoad
    self.singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapIcon:)];
    self.singleTap.numberOfTapsRequired = 1;
    self.singleTap.cancelsTouchesInView = YES;
    self.singleTap.delaysTouchesBegan = YES;
    [self addGestureRecognizer:self.singleTap];
    
    //.....code
    
    -(void)tapIcon:(UITapGestureRecognizer *)tapGesture
    {
        if (tapGesture.state == UIGestureRecognizerStateEnded){
            if (!self.timer) {
                self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2
                             target:self selector:@selector(singleTap) userInfo:nil repeats:NO];
            }else{
                [self doubleTap];
         }
    }
    

    }

    -(void)singleTap{
        [self.timer invalidate];
        self.timer = nil;
        NSLog(@"1111111111111");
    }
    
    -(void)doubleTap{
        [self.timer invalidate];
        self.timer = nil;
        NSLog(@"22222222222");
    }
    
    0 讨论(0)
  • 2020-12-05 06:40

    Here is a simple custom gesture recognizers for double taps where you can specify the maximum allowed time between taps. This is based on @Walters answer.

    PbDoubleTapGestureRecognizer.h :

    @interface PbDoubleTapGestureRecognizer : UIGestureRecognizer
    
    @property (nonatomic) NSTimeInterval maximumDoubleTapDuration;
    
    @end
    

    PbDoubleTapGestureRecognizer.m :

    #import "PbDoubleTapGestureRecognizer.h"
    #import <UIKit/UIGestureRecognizerSubclass.h>
    
    @interface PbDoubleTapGestureRecognizer ()
    @property (nonatomic) int tapCount;
    @property (nonatomic) NSTimeInterval startTimestamp;
    @end
    
    @implementation PbDoubleTapGestureRecognizer
    
    - (id)initWithTarget:(id)target action:(SEL)action {
        self = [super initWithTarget:target action:action];
        if (self) {
            _maximumDoubleTapDuration = 0.3f; // assign default value
        }
        return self;
    }
    
    -(void)dealloc {
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    }
    
    - (void)reset {
        [super reset];
    
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    
        self.tapCount = 0;
        self.startTimestamp = 0.f;
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesBegan:touches withEvent:event];
    
        if (touches.count != 1 ) {
            self.state = UIGestureRecognizerStateFailed;
        } else {
            if (self.tapCount == 0) {
                self.startTimestamp = event.timestamp;
                [self performSelector:@selector(timeoutMethod) withObject:self afterDelay:self.maximumDoubleTapDuration];
            }
            self.tapCount++;
        }
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesMoved:touches withEvent:event];
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesEnded:touches withEvent:event];
    
        if (self.tapCount > 2) {
            self.state = UIGestureRecognizerStateFailed;
        } else if (self.tapCount == 2 && event.timestamp < self.startTimestamp + self.maximumDoubleTapDuration) {
            [NSObject cancelPreviousPerformRequestsWithTarget:self];
            NSLog(@"Recognized in %f", event.timestamp - self.startTimestamp);
            self.state = UIGestureRecognizerStateRecognized;
        }
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesCancelled:touches withEvent:event];
        self.state = UIGestureRecognizerStateFailed;
    }
    
    - (void)timeoutMethod {
        self.state = UIGestureRecognizerStateFailed;
    }
    
    @end
    

    You can use it like this:

    PbDoubleTapGestureRecognizer *doubleTapGr = [[PbDoubleTapGestureRecognizer alloc]initWithTarget:self action:@selector(_doubleTapAction)];
    doubleTapGr.maximumDoubleTapDuration = 0.4;
    [yourView addGestureRecognizer:doubleTapGr];
    

    You can combine this with requireGestureRecognizerToFail: to get the behavior that was asked for.

    0 讨论(0)
  • 2020-12-05 06:42

    Swift 3.1 version of eladleb's answer.

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
            super.touchesBegan(touches, with: event)
    
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
                if self?.state != .recognized {
                    self?.state = .failed
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-05 06:52

    only thing you need to do is add extra line of code to use requireGestureRecognizerToFail

    [singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
    

    then whole code become to:

    UITapGestureRecognizer *doubleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(beginComicTransitions:)] autorelease];    
    doubleTapRecognizer.numberOfTapsRequired = 2;
    doubleTapRecognizer.numberOfTouchesRequired = 1;
    doubleTapRecognizer.delegate = self;   
    
    UITapGestureRecognizer *singleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bringMenu:)] autorelease];    
    singleTapRecognizer.numberOfTapsRequired = 1;
    singleTapRecognizer.numberOfTouchesRequired = 1;
    singleTapRecognizer.delegate = self;
    
    [singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
    

    here's requireGestureRecognizerToFail means:

    • if not recognized double tap, then single tap be recognized
    • if recognized double tap, will not recognize single tap

    swift version code is:

        let doubleTap = UITapGestureRecognizer(target: self, action: "doubleTapped:")
        doubleTap.numberOfTapsRequired = 2
        doubleTap.numberOfTouchesRequired = 1
        self.scrollView.addGestureRecognizer(doubleTap)
    
        let singleTap = UITapGestureRecognizer(target: self, action: "singleTap:")
        singleTap.numberOfTapsRequired = 1
        singleTap.numberOfTouchesRequired = 1
        self.scrollView.addGestureRecognizer(singleTap)
    
        singleTap.requireGestureRecognizerToFail(doubleTap)
    
    0 讨论(0)
  • 2020-12-05 06:54

    This is easiest to do without gesture recognizers. Then you can control the delay. The code below is a variation of Apple's original documentation that I use in one of my projects. I have blog post that talks about it as well.

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
     UITouch *touch = [touches anyObject];
    if (touch.tapCount == 2) {
    //This will cancel the singleTap action
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    }
    
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
     UITouch *touch = [touches anyObject];
    if (touch.tapCount == 1) {
      //if they tapped within the coin then place the single tap action to fire after a delay of 0.3
      if (CGRectContainsPoint(coin.frame,[touch locationInView:self.view])){
        //this is the single tap action being set on a delay
      [self performSelector:@selector(onFlip) withObject:nil afterDelay:0.3];
      }else{
       //I change the background image here
      }
     } else if (touch.tapCount == 2) {
      //this is the double tap action
      [theCoin changeCoin:coin];
     }
    }
    
    0 讨论(0)
提交回复
热议问题