How to resign first responder from text field when user tap elsewhere?

59,349

Solution 1

I found the answer here:

If your ultimate aim is just to resign the first responder, this should work: [self.view endEditing:YES]

The endEditing(_:) method is designed right for it

Causes the view (or one of its embedded text fields) to resign the first responder status.

Solution 2

For a more robust and clean solution add a tap gesture recognizer to your primary view.

This will work better with nested views and will be cleaner than secret buttons in code and UI builder.

In your view did load:

UITapGestureRecognizer* tapBackground = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard:)];
[tapBackground setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:tapBackground];

..and define your target action to be triggered on tap:

-(void) dismissKeyboard:(id)sender
{
    [self.view endEditing:YES];
}

Solution 3

Using Swift you can do this:

func viewDidLoad() {
    super.viewDidLoad()

    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.hideKeyboardByTappingOutside))
    
    self.view.addGestureRecognizer(tap)
}

@objc func hideKeyboardByTappingOutside() {
    self.view.endEditing(true)
}

Solution 4

The best option is the shortest way ;)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

Solution 5

UIViewController inherits from UIResponder so a naive way (I am pretty sure is not the smartest way to do it) would be by overwriting the following methods (at least 1 of them)

– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
- touchesCancelled:withEvent:

Next you could get the touched view by doing

UITouch *touch = [touches anyObject];
UIView *touchedView = [touch view];

finally resign the first responder if that view is not your text field

if(touchedView != textField){
    [textField resignFirstResponder];
}

_

Demerits of this approach:

You will have to handle the "tap" by yourself. (Same problem as the old iOS 3.1 or earlier). You will have to come up with your own implementation to differentiate single taps from drags, swipes, double taps, long taps, etc. Is not hard to get it working well but it is not likely you get it exactly the same way Apple detects taps (timings, distances, thresholds count!) However, that depends on your needs.

If your view structure is simple enough then you could add a gesture recognizer to the container view and resign the first responder every time the handler is called :)

Hope this helps

Share:
59,349

Related videos on Youtube

Steve
Author by

Steve

Updated on April 21, 2022

Comments

  • Steve
    Steve about 2 years

    I have filled my view with ScrollView (same size as the view) and I'm stuck at how to resign first responder when user tap elsewhere in the View (or the scrollview). Any idea on how to do that ? I'm using the following method but it's not working as expected:

    - (BOOL)textFieldShouldEndEditing:(UITextField *)textField
    {
        [textField resignFirstResponder];
        return YES;
    }
    

    Thx for helping,

    Stephane

    • user523234
      user523234 over 12 years
      Make sure you have <UITextFieldDelegate> this is your interface file.
    • Steve
      Steve over 12 years
      I added it this is why I'm using the textFieldShouldEndEditing method
    • Loukas
      Loukas over 9 years
      possible duplicate of Easy way to dismiss keyboard?
  • Steve
    Steve over 12 years
    IBOulet is to access interface object properties. What I want is to let my view controller know when a specific event occurs on a text field. An event like "mouseout" when using Javascript. Objective C seems poor at these simple things lol
  • Or Ron
    Or Ron over 12 years
    in order to resign first responder, that is exactly what u need an IBOutlet for the textfield. If you want to get this method called you should set your viewcontroller as the textFields delegate.
  • Or Ron
    Or Ron over 12 years
    Furthermore, sometimes users will want to exit from "editing" mode without pressing any button, they are used to it. you should catch touches on the background and use again either IBOutlet or pointer to this text field and make him resign first responder.
  • Or Ron
    Or Ron over 12 years
    And by the way, the point of this button is to vote whether my comment is totally irrelevant or nonsense and not if you believe I misinterpreted your question. Next time just learn to leave a comment.
  • Steve
    Steve over 12 years
    Thx for commeting. It's not me who downvoted your reply! Sorry for late reply to your comments The thing is IBOulet does not respond to events but IBAction do. What I'm looking is an event/delegate method.
  • Tom Redman
    Tom Redman over 11 years
    This is a much better solution than calling each individual input's resignFirstResponder method.
  • PassKit
    PassKit about 10 years
    Great solution, and much cleaner than a button hack.
  • Andres Canella
    Andres Canella about 10 years
    Thanks @PassKit, we tend to layer on a lot of custom UI. The simpler & cleaner the better:)
  • strange
    strange about 10 years
    The correct solution is offered by DanSkeel below, and really should be marked as the accepted answer.
  • LEAD2M
    LEAD2M almost 10 years
    This is an easy way, but this could lead unwanted impact on gestures of other objects.
  • Andres Canella
    Andres Canella almost 10 years
    In what case specifically?
  • Haagenti
    Haagenti over 9 years
    Instead of resign all fields, can't you just can [self endEditing:YES];
  • Recycled Steel
    Recycled Steel over 8 years
    Although this may (note may as I am not sure) take a little longer to execute than other methods it is very handy when needing to resign the firstResponder from a Class where the current VC is not known and so is probably quicker than finding it and so on.
  • ToolmakerSteve
    ToolmakerSteve about 7 years
    @RecycledSteel - given that iOS must always know the current firstResponder, I see no reason why this would be slow.
  • ToolmakerSteve
    ToolmakerSteve about 7 years
    But where put this line of code, so that a tap anywhere (outside of field being edited) executes it?
  • DanSkeel
    DanSkeel about 7 years
    @ToolmakerSteve e.g. you can add this code to the method that handles tap of UITapGestureRecognizer added to ViewController's view.
  • huggie
    huggie about 7 years
    This hinders UITableViewDelegate being called when user select a cell.
  • Adrian
    Adrian over 6 years
    @AlexZavatone You just put it where you need it to go. If you want to do it when the view disappears, put it in viewDidDisappear. Or perhaps you want to do it when a button is clicked, so you'd put it in the code for your button action.
  • Mike Irving
    Mike Irving over 5 years
    Much better than hidden (transparent) buttons.. and without complicating the interface builder. Thank you.