How to remove gesture recogniser

IphoneObjective CIosIpadIos4

Iphone Problem Overview


SO, I am adding a gesture recogniser to an overlay view. When tapped on screen i want this overlay to go away. Having said that adding a gesture recognizer overrides the "touch up inside" and other button click events. I need this back therefore i need to removegesturerecognizer. I can use this method however i have a problem. My code below -

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

}

Here i am taking the overlay off the other view.

- (void) dismissView
{
    UIView *overlay = [self viewWithTag:50];
    [overlay removeFromSuperview];
    self.scrollEnabled = YES;
}

My question is how do i remove the gesture recognizer in the second method? I cant pass the variable tap into this method nor can i remove it in the previous method either. Any pointers? Ive been stuck with quite a lot of passing variable problems when it comes to events.

Iphone Solutions


Solution 1 - Iphone

This loop will remove all gesture recognizers a view has

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

Solution 2 - Iphone

Declare an ivar UITapGestureRecognizer *tap in your @interface.

Change helpClicked to:

- (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];  
}

and dismissView to:

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

EDIT: i think nhahtdh's method is a bit more elegant compared to this one.

EDIT2: it seems you have [self addGestureRecognizer:tap] working so i'm asumming this is a subclass of UIView.

Solution 3 - Iphone

From the WWDC 2015, Cocoa Touch Best Practices, it is suggested that you keep a property or iVar if you need to access it later, and don't go with using viewWithTag:.

##Moto: Properties instead of Tags

This saves you from some trouble:

  1. When dealing with multiple gestures, you remove the gesture that you want directly with accessing the property and remove it. (Without the need to iterate all the view's gestures to get the correct one to be removed)
  2. Finding the correct gesture by the tag when you are iterating, is very misleading when you have multiple tags on views, and when having conflicts with a specific tag

> (i.e) You implemented it first time with tags, and everything works > as expected. Later you work on another functionality which lets say > breaks this and causes undesired behavior that you don't expect it. Log > doesn't give you a warning, and the best thing you can get depending on the case it's a crash signalizing unrecognized selector sent to instance. Sometimes you won't get any of these.

##Solution

Declare the iVar

@implementation YourController {
    UITapGestureRecognizer *tap;
}

Setup your view

- (void) helpClicked {
    //Your customization code
    
    //Adding tap gesture
    tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissView)];
    [self addGestureRecognizer:tap];
}

Remove the gesture directly

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

Solution 4 - Iphone

Swift version:

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

Solution 5 - Iphone

Just set up the overlay view once, with the gesture recognizer set up, but make the overlay view hidden. When a view is hidden, it won't receive any touch from user. Only make the overlay view visible the view when necessary, and make it hidden when you don't need it.

Solution 6 - Iphone

Your code should probably look more like this, for the second method:

- (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;
}

I added the check for UITapGestureRecognizer, in case your class handles more than 1 UIGestureRecognizers and you only want to remove that.

Solution 7 - Iphone

This work for me:

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

Solution 8 - Iphone

In 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
        }
    }

Solution 9 - Iphone

If you are able to extend the view you could try this way:

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

Solution 10 - Iphone

It worked for me.

while (view.gestureRecognizers.count) {
  [view removeGestureRecognizer:[view.gestureRecognizers objectAtIndex:0]];
}

Solution 11 - Iphone

Nifty Swifty one-liner form:

    yourView.gestureRecognizers?.forEach { yourView.removeGestureRecognizer($0) }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCodeGeek123View Question on Stackoverflow
Solution 1 - IphoneOmar AbdelhafithView Answer on Stackoverflow
Solution 2 - IphoneRok JarcView Answer on Stackoverflow
Solution 3 - IphoneE-RiddieView Answer on Stackoverflow
Solution 4 - IphonebudiDinoView Answer on Stackoverflow
Solution 5 - IphonenhahtdhView Answer on Stackoverflow
Solution 6 - IphoneskramView Answer on Stackoverflow
Solution 7 - IphoneMatheus VelozaView Answer on Stackoverflow
Solution 8 - IphoneiOS LifeeView Answer on Stackoverflow
Solution 9 - IphoneFran PuglView Answer on Stackoverflow
Solution 10 - IphoneAdeel IshaqView Answer on Stackoverflow
Solution 11 - IphoneclearlightView Answer on Stackoverflow