如何使用UITapGestureRecognizer检测同时发生的单击和双击?

14

例如,我有一个视图,希望实现两种不同的手势:

单击执行操作A。 双击执行操作B。

问题在于使用UITapGestureRecognizer时,我只能设置最小所需的点击次数。单击手势识别器会在双击手势识别器之前识别一个点击。

示例:

_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognized:)];
_tapGestureRecognizer.numberOfTouchesRequired = 1;
_tapGestureRecognizer.numberOfTapsRequired = 1;
[self addGestureRecognizer:_tapGestureRecognizer];

_doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestureRecognized:)];
_doubleTapGestureRecognizer.numberOfTouchesRequired = 1;
_doubleTapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:_doubleTapGestureRecognizer];

即使我快速地进行了双击,它总是识别为单击。我该如何设置它,让单击手势识别器等待并查看是否双击手势识别器会被识别?


可能的解决方案和重复问题:https://dev59.com/qGw05IYBdhLWcg3wiybg - xarly
尝试这个来消除延迟或根据您需要进行调整。 https://dev59.com/rmsz5IYBdhLWcg3wNVAR#25368653 - Pagly
5个回答

50

以下是我在以前的项目中使用的内容,希望能对你有所帮助。

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

 UITapGestureRecognizer *doubleTap = [[[UITapGestureRecognizer alloc] initWithTarget:   self action:@selector(doDoubleTap)] autorelease];
 doubleTap.numberOfTapsRequired = 2; 
 [self.view addGestureRecognizer:doubleTap];

  [singleTap requireGestureRecognizerToFail:doubleTap];

10
这个功能可以使用,但是在单次轻触时会导致延迟。 - Mrug
1
有人找到了解决这个延迟的方法吗? - barfoon
对于像@barfoon这样仍然有取消双击延迟的人,请参考eladleb提供的解决方案:https://dev59.com/rmsz5IYBdhLWcg3wNVAR#23415324,并使用双击手势的子类,以便更快地发送“状态失败”。 - Michael Pirotte

8

关于Swift 3和Swift 4:

let singleTap = UITapGestureRecognizer(target: self, action: #selector(doSingleTap))
singleTap.numberOfTapsRequired = 1

self.view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action: #selector(doDoubleTap))
doubleTap.numberOfTapsRequired = 2

self.view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

我使用singleTap.requireGestureRecognizerToFail(doubleTap)代替singleTap.require(toFail: doubleTap)。 - Marcos
答案是针对Swift 3的@Marcos。 - Logan

0
另一个选择是使用 UIGestureRecognizerDelegate,特别是当您无法轻松访问其他识别器时。
let singleTap = UITapGestureRecognizer(target: self, action: #selector(doSingleTap))
singleTap.numberOfTapsRequired = 1
singleTap.delegate = self
self.view.addGestureRecognizer(singleTap)

实现代理:

extension ViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if let tapGesture = gestureRecognizer as? UITapGestureRecognizer, let otherTapGesture = otherGestureRecognizer as? UITapGestureRecognizer {
            return tapGesture.numberOfTapsRequired == 1 && otherTapGesture.numberOfTapsRequired == 2
        }
        return false
    }
}

0
   {  UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
        [doubleTap setDelegate:self];
        doubleTap.numberOfTapsRequired = 2;
        [self.headerView addGestureRecognizer:doubleTap];

        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
        singleTap.numberOfTapsRequired = 1;
        [singleTap setDelegate:self];
        [doubleTap setDelaysTouchesBegan:YES];
        [singleTap setDelaysTouchesBegan:YES];
        [self.headerView addGestureRecognizer:singleTap];
  }  
        - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
            return  YES;
        }

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
        return YES;
    }

在任何你想要的方法中创建手势识别器。例如,如果你想要为tableView的headerView创建点击手势,在那些方法中创建这些点击手势即可。
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

而且你的类应该实现UIGestureRecognizerDelegate。 上述是该委托类的两种方法。


一些解释会显著提高你的回答质量。 - mrun

-1
我找到了一个解决单击延迟的方法,采用了XCode Monkey的答案。使用这种方法,您可以在毫秒级别上配置单击和双击之间的阈值。该技术使用一个简单的UIButton和NSTimer来区分单击和双击。
@property NSTimer       *tapTimer;
@property BOOL           isDoubleTap;

  UIButton *yourButton = [UIButton new];
  yourButton.frame = // set your frame
  [yourButton addTarget:self action:@selector(handleTap:) forControlEvents:UIControlEventTouchUpInside];
  [self.view yourButton];


-(void)handleTap:(UIButton*)button
{
  [self.tapTimer invalidate];

  if (self.isDoubleTap)
  {
    [self doDoubleTap];
    return;
  }
  self.isDoubleTap = YES;
  // CHANGE THE 0.3 SECOND THRESHOLD BETWEEN SINGLE/DOUBLE TAP TO YOUR HEART'S CONTENT
  self.tapTimer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(doSingleTap) userInfo:nil repeats:NO];
}

-(void)doSingleTap
{
  self.isDoubleTap = NO;
}

-(void)doDoubleTap
{
  self.isDoubleTap = NO;
}

1
没有延迟改善,同时会导致用户在不到0.3秒的时间内点击多个单元格时出现潜在问题。 - ChuckKelly
你必须保持一个显著的(0.2)延迟,否则双击检测无法在单击计时器到期之前注册。 - Jeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接