UITapGestureRecognizer-单击和双击


156

我正在尝试向UITapGestureRecognizers视图添加2 ,一个用于单击,一个用于双击事件。单抽头识别器正在按预期运行(单独运行)。但是我似乎无法使双击识别器正常工作。

已经尝试具有类似性质的实验:cancelsTouchesInViewdelaysTouchesBegandelaysTouchesEnded,但仍然无法正常工作。

当我双击时,单击识别器将始终被激活,并且双击事件也将发送到超级视图。但是自定义双击识别器似乎根本没有得到通知。

文档似乎表明可以将上述3个属性用于此目的。但是我不确定应该设置哪些值以及在哪些识别器上(单,双或双)。希望有人对此有所帮助。

以下是最新更新的代码块。

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}

30
随机评论:变量名中的下划线将使大多数Objective-C程序员畏缩。更糟糕的是,您的变量名没有描述性。为什么不只使用singleTapRecognizer和doubleTapRecognizer(或类似的东西)?键入需要花费一秒钟的时间,但是会使您的代码无限地可读。
UIAdam

感谢您的建议,同意您的观点,变量名称应更具描述性。但是这个特定的代码段尚未完成,并将按照建议发布更精美的描述性代码...
Stanley 2012年

万一其他人有类似的问题。我很难让快速识别器和双击识别器一起工作(单次操作正常,但没有两次操作)。我使用情节提要将识别器拖到场景上。我在viewDidLoad中有处理程序和语句:singleTapRecognizer.requireGestureRecognizerToFail(doubleTabRecognizer),但仍然没有双击。我缺少的难题是将双击识别器图标(从场景的顶部行)拖到要识别双击的视图部分上。
Paulus

1
@UIAdam使用下划线在objc中为私有ivar名称添加前缀是相当普遍的,尽管不是吗?(来自迅速的背景)
Charlton Provatas

Answers:


412
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];

注意: 如果要使用 numberOfTouchesRequired ,必须 .numberOfTouchesRequired = 1;

对于斯威夫特

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)

感谢您的回答,尝试过您的代码,但仍然无法正常工作。肯定还有我想念的东西。您还有其他提示吗?
斯坦利

我可以为此提供您的实施文件吗?
阿尼尔·科塔里

@Stanley:Anils的答案应该可行,当然,您还必须提供处理程序(doSingleTap,doDoubleTap)
Rok Jarc 2012年

轻按一下即可更新一个UITableView,该UITableView可以按预期工作。双击当前仅使用NSLog输出一条日志语句。我的怀疑是,第一次响应者的状态从UIView变为第一次点击后的其他位置,因为我没有对响应链进行任何明确的操作。
斯坦利

6
该解决方案对我有用。一段时间后会触发单选开关。
弗拉基米尔·奥布里赞

46

Swift 3解决方案:

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

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

singleTap.require(toFail: doubleTap)

在代码行singleTap.require(toFail:doubleTap)中,我们强制单击以等待,并确保tap事件不是双击。


31

您需要使用requireGestureRecognizerToFail:方法。像这样:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


刚刚尝试再次使用两个识别器调用“失败”方法。但是仍然不起作用。如果您之前可以使用双击功能,请与我分享更多经验。
斯坦利

1
我已经尝试了这个确切的代码(与Anil更为详细地发布的代码相同),并且对我有用。
UIAdam

感谢您的评论,那么我仍然必须错过某些事情……
Stanley

您的代码仍然与delaysTouches之类的混乱。使其完全遵循Anil的代码。仅在我们拥有它后才使用requireGestureRecognizerToFail。
UIAdam

由于目前时间有限,请按照您今天或明天的建议进行操作。感谢您的协助...
Stanley

15

// ----首先,您必须分配双击手势------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleSingleTap:)];

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// -----------------------抽头数---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// -------在视图或按钮上添加双击和单击手势-------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

不知道这是否正是您要寻找的东西,但是我在没有手势识别器的情况下进行了单次/双击操作。我在UITableView中使用它,所以我在didSelectRowAtIndexPath方法中使用了该代码

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

使用NSIndexPath作为参数,方法singleTap和doubleTap都无效:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

希望能帮助到你


感谢您的回答,@ Novarg。您是否有关于doubleTap识别器的问题?
斯坦利

@Stanley不,singleTap在发射前等待0.2秒。如果同时激活了第二个点击,则取消singleTap方法。
Novarg 2012年

看起来非常有前途,感谢您的协助。今天又没时间了。明天一定会尝试的:)
Stanley

创造性的答案;)
迈克尔·迈克尔(Michael

非常好的解决方案。我只需要在每个处理程序(singleTap,doubleTap)上添加tapCount = 0,以确保可以识别以下触摸。
西里奥(Sirio),

3

Swift 2解决方案:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)

1

我实现了UIGestureRecognizerDelegate方法来检测singleTap和doubleTap。

只要做这个。

 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];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

然后实现这些委托方法。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

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

0

一些视图具有内置的双击识别器(MKMapView作为示例)。为了解决这个问题,您将需要实现UIGestureRecognizerDelegatemethod shouldRecognizeSimultaneouslyWithGestureRecognizer并返回YES

首先实现您的双重和单一识别器:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

然后执行:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }

-1

关于@stanley的评论-

不要尝试使用点击手势来对行进行选择,UITableView因为它已经具有完整的点击处理功能...。

但是,您必须在单击手势识别器上将“取消视图中的触摸”设置为“否”,否则它将永远不会收到触摸事件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.