Detect tap on UIView's "empty space"
Asked Answered
E

4

10

I've got a view hierarchy that looks like that

UIScrollView
 |
 +- UIView
     |
     +- UITextField
     +- UITextField
     +- UIButton

What I want is for user which tapped one of the text fields and sees the keyboard on the screen to be able to tap on an "empty space" of UIView to hide keyboard. So, I don't want, for instance, an event from UIButton to bubble up to UIView (that's exactly what happens if I add UITapGestureRecognizer to UIView).

How can I achieve the desired functionality?

Electrodeposit answered 19/6, 2012 at 13:0 Comment(0)
M
23

In your viewDidLoad method add this gesture recognizer:

UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
gestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:gestureRecognizer];

Then add the dismissKeyboard method:

- (void) dismissKeyboard{
   [YOURFIELDHERE resignFirstResponder];
} 

You also need to add this to make it so the buttons are still clickable and not overridden by the gesture recognizer:

gestureRecognizer.delegate = self; // in viewDidLoad
<UIGestureRecognizerDelegate> //in your header file

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

  if ([touch.view isKindOfClass:[UIButton class]]){
    return NO;
  }
  return YES; // handle the touch
}
Mouthy answered 19/6, 2012 at 13:6 Comment(3)
The GestureRecognizer's delegate is something I haven't been using. Instead I used silly subclassing to process touches, this could have been done so much more easier. Thank you.Erfurt
I've made that mistake more than once. Re-invented the wheel, and not very elegantly at that, only to find there was a delegate method that did what I wanted even better than I had managed to accomplish. It is a real downfall of Apple's documentation, in my opinion.Mouthy
This works beautifully. No hacks, no subclasses, just clean code. Thank you.Threedecker
D
1

I encounter this same problem and solve it with a naive solution.

  1. Change the View from an instance of UIView to an instance of UIControl so that it can handle touch events.
  2. Create an IBAction method in the View Controller that handles the touch event. In this case, we will resign any first responder from the view's subviews.

    - (IBAction)backgroundTapped:(id)sender { [contentView endEditing:YES]; }

    contentView is just the instance variable pointing to the View. You can name it anything you want. When you passed the message endEditing to the View, it essentially tells its subviews to resign first responder, thus dismissing the keyboard.

  3. Connect the target (View) and action (IBAction method you just created) via Interface Builder, by opening the connection inspector of the View, select Touch Up Inside and drag it to the File's Owner object, then select the name of the method.

Hopefully it helps.

Deport answered 19/11, 2012 at 15:33 Comment(0)
Q
1

I know it's a little late, but a quick, simple solution is the following:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    [self.view endEditing:YES];
}

It gets called if you tap on any empty space.

Quirk answered 10/9, 2013 at 22:32 Comment(0)
M
0

Mike Z's answer is good. But I think the "if condition" below would be easier and simple in UIGestureRecognizerDelegate when you use Mike Z's answer.

Especially when the subviews are not only a button type, they may also be UITableViewCell, Custom View, etc.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    return touch.view == yourEmptySpaceView;
}
Moradabad answered 28/12, 2021 at 9:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.