如何移除手势识别器

52

因此,我正在为叠加视图添加手势识别器。当在屏幕上轻击时,我希望该叠加视图消失。但是,添加手势识别器会覆盖“touch up inside”和其他按钮点击事件。因此,我需要将其删除以恢复这些事件。我可以使用下面的方法,但我遇到了问题-

- (void)helpClicked
{
    CGRect visibleBounds = [self convertRect:[self bounds] toView:viewContainer];
    CGFloat minimumVisibleX = CGRectGetMinX(visibleBounds);
    UIImageView * helpOverlay = [[UIImageView alloc]initWithFrame:CGRectMake(minimumVisibleX, 0, 1024, 768)];
    UIImage * helpImage = [UIImage imageNamed:@"HelpOverLay.png"];
    [helpOverlay setImage:helpImage];
    helpOverlay.tag = 50;
    self.scrollEnabled = NO;
    [self addSubview:helpOverlay]; 
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] 
                               initWithTarget:self
                               action:@selector(dismissView)];

[self addGestureRecognizer:tap];    
在这里我正在将覆盖视图从另一个视图上移除。
- (void) dismissView
{
    UIView *overlay = [self viewWithTag:50];
    [overlay removeFromSuperview];
    self.scrollEnabled = YES;
}
我的问题是如何在第二个方法中删除手势识别器?我无法将变量“tap”传递到此方法中,也无法在之前的方法中删除它。有什么指针吗?当涉及到事件时,我一直被卡住了很多传递变量的问题。

2
你可以保留对 tap 的引用(可能作为 ivar),这样你就可以安全地在需要时随时删除它。 - Rok Jarc
11个回答

108

这个循环将删除视图上的所有手势识别器。

for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
    [self.view removeGestureRecognizer:recognizer];
}

3
正确答案,不需要使用变量来保留手势...谢谢。 - meronix
为什么不应该这样做?for (UIGestureRecognizer *recognizer in self.view.window.gestureRecognizers) { [self.view.window removeGestureRecognizer:recognizer]; } - MiQUEL
这是正确的答案。我正在一个SpriteKit游戏中使用手势,当一个新场景被呈现时,识别器仍然有效。当它们在新场景中找不到目标时会导致崩溃。 - Beau Nouvelle
1
这也会移除表视图和标准 iOS 控制器添加的任何手势,所以请注意。 - DustinB

31
WWDC 2015, Cocoa Touch 最佳实践中建议如果需要以后访问属性或iVar,则应将其保留,并不要使用viewWithTag:

原则:使用属性而不是标签

这可以避免一些麻烦:

  1. 在处理多个手势时,通过访问属性并删除它,您可以直接移除所需的手势(无需迭代所有视图的手势以获取要删除的正确手势)。
  2. 当您在视图上具有多个标记,并且与特定标记发生冲突时,通过标记查找正确的手势非常具有误导性。

(即)您首先使用标记实现它,一切都按预期工作。稍后,您将在另一个功能上工作,该功能会导致意外行为,您不希望出现这种情况。日志不会给你警告,根据情况,你能得到最好的东西就是崩溃信号,表明未识别的选择器发送到实例有时您将得不到任何提示

解决方案

声明iVar

@implementation YourController {
    UITapGestureRecognizer *tap;
}

设置您的视图

- (void) helpClicked {
    //Your customization code

    //Adding tap gesture
    tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissView)];
    [self addGestureRecognizer:tap];
}

直接删除手势

- (void) dismissView {
    [self.view removeGestureRecognizer:tap];
}

30
在你的@interface中声明一个UITapGestureRecognizer *tap的变量,名为ivar
helpClicked更改为:
- (void)helpClicked
{
    CGRect visibleBounds = [self convertRect:[self bounds] toView:viewContainer];
    CGFloat minimumVisibleX = CGRectGetMinX(visibleBounds);
    UIImageView * helpOverlay = [[UIImageView alloc]initWithFrame:CGRectMake(minimumVisibleX, 0, 1024, 768)];
    UIImage * helpImage = [UIImage imageNamed:@"HelpOverLay.png"];
    [helpOverlay setImage:helpImage];
    helpOverlay.tag = 50;
    self.scrollEnabled = NO;
    [self addSubview:helpOverlay]; 
    tap = [[UITapGestureRecognizer alloc] 
                               initWithTarget:self
                               action:@selector(dismissView)];

    [self addGestureRecognizer:tap];  
}

并将 dismissView 更改为:

for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
    [self removeGestureRecognizer:tap];
}

编辑:我认为nhahtdh的方法比这个更优雅。

编辑2:看起来你已经使[self addGestureRecognizer:tap]工作了,所以我假设这是UIView的一个子类。


你好,根据某些事件不断添加和删除视图手势是否公平?请告诉我。 - Exploring
@搜索:这通常是一种“快速而肮脏”的解决方案,有更好、更优雅的替代方案。这真的取决于用户界面。 - Rok Jarc
谢谢您的评论。请问您能否给我一些例子,因为当我添加tapgesture时,按钮就无法使用了。 - Exploring
1
我猜你应该发布一个带有问题描述和你正在使用的代码的问题。一个可能存在的问题是按钮已经在自己处理触摸,而这些触摸可能永远不会到达你的手势识别器。 - Rok Jarc

7

Swift版本:

if let recognizers = yourView.gestureRecognizers { 
  for recognizer in recognizers {
    yourView.removeGestureRecognizer(recognizer)
  }
}

5

只需设置一次覆盖视图,安装手势识别器,但将覆盖视图隐藏。当视图被隐藏时,它将不接收任何用户触摸。仅在需要时使覆盖视图可见,并在不需要时将其隐藏。


5
您的代码应该更像第二种方法,示例如下:
- (void) dismissView {
  UIView *overlay = [self viewWithTag:50];

  for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
    if([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
      [self removeGestureRecognizer:recognizer];
    }
  }

  [overlay removeFromSuperview];
  self.scrollEnabled = YES;
}

我添加了对UITapGestureRecognizer的检查,以防您的类处理多个UIGestureRecognizer且您只想删除该手势。


3
这对我有效:
注:该句中的HTML标签已保留。
for (UIGestureRecognizer *gr in self.view.gestureRecognizers) {
  [self.view removeGestureRecognizer:gr];
}

2

在Swift 4中

if let gestures = shotButton.gestureRecognizers //first be safe if gestures are there
    {
        for gesture in gestures //get one by one
        {
            shotButton.removeGestureRecognizer(gesture) //remove gesture one by one
        }
    }

1

如果您能够扩展视图,可以尝试以下方法:

_ = gestureRecognizers.flatMap { $0.map { removeGestureRecognizer($0) } }

1
巧妙简洁的一行代码:
    view?.forEach { view.removeGestureRecognizer($0) }

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