How to resign first responder from text field when user tap elsewhere?
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
Related videos on Youtube
Steve
Updated on April 21, 2022Comments
-
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 over 12 yearsMake sure you have
<UITextFieldDelegate>
this is your interface file. -
Steve over 12 yearsI added it this is why I'm using the textFieldShouldEndEditing method
-
Loukas over 9 yearspossible duplicate of Easy way to dismiss keyboard?
-
-
Steve over 12 yearsIBOulet 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 over 12 yearsin 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 over 12 yearsFurthermore, 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 over 12 yearsAnd 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 over 12 yearsThx 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 over 11 yearsThis is a much better solution than calling each individual input's
resignFirstResponder
method. -
PassKit about 10 yearsGreat solution, and much cleaner than a button hack.
-
Andres Canella about 10 yearsThanks @PassKit, we tend to layer on a lot of custom UI. The simpler & cleaner the better:)
-
strange about 10 yearsThe correct solution is offered by DanSkeel below, and really should be marked as the accepted answer.
-
LEAD2M almost 10 yearsThis is an easy way, but this could lead unwanted impact on gestures of other objects.
-
Andres Canella almost 10 yearsIn what case specifically?
-
Haagenti over 9 yearsInstead of resign all fields, can't you just can [self endEditing:YES];
-
Recycled Steel over 8 yearsAlthough 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 about 7 years@RecycledSteel - given that iOS must always know the current firstResponder, I see no reason why this would be slow.
-
ToolmakerSteve about 7 yearsBut where put this line of code, so that a tap anywhere (outside of field being edited) executes it?
-
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 about 7 yearsThis hinders UITableViewDelegate being called when user select a cell.
-
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 over 5 yearsMuch better than hidden (transparent) buttons.. and without complicating the interface builder. Thank you.