How to remove gesture recogniser

70,813

Solution 1

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 2

This loop will remove all gesture recognizers a view has

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

Solution 3

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 4

Swift version:

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

Solution 5

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.

Share:
70,813
CodeGeek123
Author by

CodeGeek123

Updated on July 09, 2022

Comments

  • CodeGeek123
    CodeGeek123 almost 2 years

    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.

  • meronix
    meronix almost 12 years
    right answer, no need to use a var to retain the gesture... tks
  • Exploring
    Exploring almost 11 years
    Hi is it fair enough to keep adding and removing gestures from a view based on some events? Please let me know.
  • Rok Jarc
    Rok Jarc almost 11 years
    @Searching: this is most often "quick & dirty" solution that has a better and more elegant alternative. it really depends on UI.
  • Exploring
    Exploring almost 11 years
    Thanks for your comment. Please could you give me some example, because while I'm adding tapgesture then buttons are not working.
  • Rok Jarc
    Rok Jarc almost 11 years
    I guess you should post a question with some description of your problem and code that you're using. One problem that comes to mind is that buttons are already processing touches on their own and this touches probably never get to your gesture recognizers.
  • MiQUEL
    MiQUEL over 10 years
    Why It shouldnt be? for (UIGestureRecognizer *recognizer in self.view.window.gestureRecognizers) { [self.view.window removeGestureRecognizer:recognizer]; }
  • Beau Nouvelle
    Beau Nouvelle over 10 years
    This is the correct answer. I'm using gestures in a SpriteKit game, and when a new scene is presented, the recognisers are still in effect. Causing crashes when they can't find a target in the new scene.
  • DustinB
    DustinB about 8 years
    This also removes scroll gestures for tableviews and any other gestures added by standard iOS controllers, so beware.