Reputation: 7809
I'm wondering how to make the keyboard disappear when the user touches outside of a UITextField
.
Upvotes: 493
Views: 281626
Reputation: 4959
Objective-C:
Add this code in your ViewController.m file :
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
Swift:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
Upvotes: 5
Reputation: 958
For collection view:
// the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
collectionView.keyboardDismissMode = .interactive
// dismisses the keyboard when a drag begins
collectionView.keyboardDismissMode = .onDrag
Upvotes: 0
Reputation: 3098
There is one thing to important...
adding gesture recognize to view can subview override it.. So only one action is performed.. If you want to perform recognize multiple action through superview and subview... You have to use
tap.cancelsTouchesInView = false
Full code is below:
let tap = UITapGestureRecognizer(target: self, action: #selector(self.superViewClicked))
tap.numberOfTapsRequired = 1
tap.delegate = self
tap.cancelsTouchesInView = false
self.view.addGestureRecognizer(tap)
@objc func superViewClicked(){
self.searchTF.resignFirstResponder()
}
What is best solution for dissmis soft keyboard on outside click?
I will explain for one condition:
Think about it : You have UISearchBar on the top, then tableview with header added!
Solution is simple:
Full code:
var isSoftKeyboardActive = false
override func viewDidLoad() {
var tap = UITapGestureRecognizer(target: self, action: #selector(self.tableHeaderClick))
tap.numberOfTapsRequired = 1
tap.delegate = self
tap.cancelsTouchesInView = false
self.headerOfTableView.addGestureRecognizer(tap)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear), name: UIResponder.keyboardWillShowNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isSoftKeyboardActive == true{
self.searchTF.resignFirstResponder()
}else{
selectedRow = indexPath.row
performSegue(withIdentifier: "segueWebview", sender: self)
}
}
@objc func tableHeaderClick(){
self.searchTF.resignFirstResponder()
}
@objc func keyboardWillAppear() {
isSoftKeyboardActive = true
}
@objc func keyboardWillDisappear() {
isSoftKeyboardActive = false
}
How is it work:
Upvotes: 1
Reputation: 8408
You'll need to add an UITapGestureRecogniser
and assign it to the view, and then call resign first responder on the UITextField
on it's selector.
The code:
In viewDidLoad
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
In dismissKeyboard:
-(void)dismissKeyboard
{
[aTextField resignFirstResponder];
}
(Where aTextField
is the textfield that is responsible for the keyboard)
Swift 3 version looks like that
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard (_:)))
self.view.addGestureRecognizer(tapGesture)
For dismissKeyboard
@objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
aTextField.resignFirstResponder()
}
Upvotes: 793
Reputation: 975
In swift 5 You can use following code to dismiss keyboard outside textfield
override func viewDidLoad() {
// ... code
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard(_:)))
self.view.addGestureRecognizer(tapGesture)
}
@objc func dismissKeyboard(_ sender: UITapGestureRecognizer) {
self.view.endEditing(true)
}
Upvotes: 5
Reputation: 1078
In viewDidLoad swift 4.2 The code like this
let viewTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action:#selector(dismissKeyboard))
view.addGestureRecognizer(viewTap)
@objc func dismissKeyboard() {
view.endEditing(true)
}
Upvotes: 0
Reputation: 2980
I tried many of the responses here and had no luck. My tap gesture recognizer was always causing my UIButtons
to not respond when tapped, even when I set the cancelsTouchesInView
property of the gesture recognizer to NO.
This is what eventually solved the issue:
Have an ivar:
UITapGestureRecognizer *_keyboardDismissGestureRecognizer;
When a text field begins editing, set the gesture recognizer:
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
if(_keyboardDismissGestureRecognizer == nil)
{
_keyboardDismissGestureRecognizer = [[[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(dismissKeyboard)] autorelease];
_keyboardDismissGestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:_keyboardDismissGestureRecognizer];
}
}
Then the trick is in how you set up the dismissKeyboard
method:
- (void) dismissKeyboard
{
[self performSelector:@selector(dismissKeyboardSelector) withObject:nil afterDelay:0.01];
}
- (void) dismissKeyboardSelector
{
[self.view endEditing:YES];
[self.view removeGestureRecognizer:_keyboardDismissGestureRecognizer];
_keyboardDismissGestureRecognizer = nil;
}
I guess there's just something about getting the dismissKeyboardSelector
execution out of the touch handling execution stack...
Upvotes: 2
Reputation: 1365
Swift 4 oneliner
view.addGestureRecognizer(UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:))))
Upvotes: 15
Reputation: 5304
How about this: I know this is an old post. It might help someone :)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *subviews = [self.view subviews];
for (id objects in subviews) {
if ([objects isKindOfClass:[UITextField class]]) {
UITextField *theTextField = objects;
if ([objects isFirstResponder]) {
[theTextField resignFirstResponder];
}
}
}
}
Upvotes: 17
Reputation: 1075
I see that some people are having issues using the UITapGestureRecognizer
method. The easiest way that I've accomplished this functionality while still leaving my existing button's tap behavior intact is adding only one line to @Jensen2k 's answer:
[tap setCancelsTouchesInView:NO];
This allowed my existing buttons to still work without using @Dmitry Sitnikov 's method.
Read about that property
here (search for CancelsTouchesInView
): UIGestureRecognizer Class Reference
I'm not sure how it would work with scrollbars, as I see some had issues with, but hopefully someone else might run into the same scenario I had.
Upvotes: 90
Reputation: 1923
It is better to make your UIView
an instance of UIControl
(in interface builder) and then connect their TouchUpInside
event to dismissKeyboard
method. This IBAction
method will look like:
- (IBAction)dismissKeyboard:(id)sender {
[aTextBox resignFirstResponder];
}
Upvotes: 56
Reputation: 9368
I mashed up a few answers.
Use an ivar that gets initialized during viewDidLoad:
UIGestureRecognizer *tapper;
- (void)viewDidLoad
{
[super viewDidLoad];
tapper = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleSingleTap:)];
tapper.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:tapper];
}
Dismiss what ever is currently editing:
- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
[self.view endEditing:YES];
}
Upvotes: 181
Reputation: 2180
Swift 4
Setup your UIViewController
with this extension method once e.g in viewDidLoad
:
override func viewDidLoad() {
super.viewDidLoad()
self.setupHideKeyboardOnTap()
}
and the keyboard will be dismissed even by tapping on the NavigationBar
.
import UIKit
extension UIViewController {
/// Call this once to dismiss open keyboards by tapping anywhere in the view controller
func setupHideKeyboardOnTap() {
self.view.addGestureRecognizer(self.endEditingRecognizer())
self.navigationController?.navigationBar.addGestureRecognizer(self.endEditingRecognizer())
}
/// Dismisses the keyboard from self.view
private func endEditingRecognizer() -> UIGestureRecognizer {
let tap = UITapGestureRecognizer(target: self.view, action: #selector(self.view.endEditing(_:)))
tap.cancelsTouchesInView = false
return tap
}
}
Upvotes: 49
Reputation: 1328
Swift version of @Jensen2k's answer:
let gestureRecognizer : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: "dismissKeyboard")
self.view.addGestureRecognizer(gestureRecognizer)
func dismissKeyboard() {
aTextField.resignFirstResponder()
}
One liner
self.view.addTapGesture(UITapGestureRecognizer.init(target: self, action: "endEditing:"))
Upvotes: 3
Reputation: 5850
I think the easiest (and best) way to do this is to subclass your global view and use hitTest:withEvent
method to listen to any touch. Touches on keyboard aren't registered, so hitTest:withEvent is only called when you touch/scroll/swipe/pinch... somewhere else, then call [self endEditing:YES]
.
This is better than using touchesBegan
because touchesBegan
are not called if you click on a button on top of the view. It is better than UITapGestureRecognizer
which can't recognize a scrolling gesture for example. It is also better than using a dim screen because in a complexe and dynamic user interface, you can't put dim screen everywhere. Moreover, it doesn't block other actions, you don't need to tap twice to select a button outside (like in the case of a UIPopover
).
Also, it's better than calling [textField resignFirstResponder]
, because you may have many text fields on screen, so this works for all of them.
Upvotes: 10
Reputation: 4947
Swift version, this works in combination with other elements (like a UIButton
or another UITextField
):
override func viewDidLoad() {
super.viewDidLoad()
let tapper = UITapGestureRecognizer(target: self, action:#selector(endEditing))
tapper.cancelsTouchesInView = false
view.addGestureRecognizer(tapper)
}
Upvotes: 28
Reputation: 1280
For those struggling with this in Swift. This is the accepted answer by Jensen2k but in Swift.
Swift 2.3
override func viewDidLoad() {
//.....
let viewTapGestureRec = UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))
//this line is important
viewTapGestureRec.cancelsTouchesInView = false
self.view.addGestureRecognizer(viewTapGestureRec)
//.....
}
func handleViewTap(recognizer: UIGestureRecognizer) {
myTextField.resignFirstResponder()
}
Upvotes: 1
Reputation: 1196
Set text fields delegate in view did load:
override func viewDidLoad()
{
super.viewDidLoad()
self.userText.delegate = self
}
Add this Function:
func textFieldShouldReturn(userText: UITextField!) -> Bool
{
userText.resignFirstResponder()
return true;
}
Upvotes: 1
Reputation: 79
You can use UITapGestureRecongnizer method for dismissing keyboard by clicking outside of UITextField. By using this method whenever user will click outside of UITextField then keyboard will get dismiss. Below is the code snippet for using it.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(dismissk)];
[self.view addGestureRecognizer:tap];
//Method
- (void) dismissk
{
[abctextfield resignFirstResponder];
[deftextfield resignFirstResponder];
}
Upvotes: 1
Reputation: 1531
In this case, there can be use ScrollView and added to TextField
in ScrollView and I want Tap the ScrollView
and View then Dismiss the Keyboard. I tried to create sample code just in case. Like this,
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:)))
view.addGestureRecognizer(tapGesture)
// Do any additional setup after loading the view, typically from a nib.
}
func tap(gesture: UITapGestureRecognizer) {
textField.resignFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your Storyboard Look at that Just Like.
Upvotes: 1
Reputation: 1233
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first{
view.endEditing(true)
}
}
Upvotes: 2
Reputation: 395
This must be the easiest way to hide your keyboard by touching outside :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
(from How to dismiss keyboard when user tap other area outside textfield?)
Upvotes: 9
Reputation: 17612
So I just had to solve this very problem, and none of the previous answers worked for me out of the box. My situation: a UISearchBar
, plus a number of other controls on the screen. I want for a tap outside of the search bar to dismiss the keyboard, but not propagate to any of the other controls. When the keyboard is hidden, I want all the controls to work.
What I did:
1) Implement a custom touch handler in my view controller.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
if searchBar.isFirstResponder()
{
// This causes the first responder, whoever it is, to resign first responder, and hide the keyboard.
// We also "eat" the touch here and not allow it to propagate further.
view.endEditing(true)
}
else
{
// OK to propagate the touch
super.touchesBegan(touches, withEvent: event)
}
}
2) Added a couple of delegate methods (mine are for the UISearchBar, but there are similar ones for UITextField). controlContainerView
in the code below is a UIView that has a bunch of buttons in it. Remember that setting userInteractionEnabled
on a superview disables all its subviews.
func searchBarTextDidBeginEditing(searchBar: UISearchBar)
{
controlContainerView.userInteractionEnabled = false
someButton.userInteractionEnabled = false
}
func searchBarTextDidEndEditing(searchBar: UISearchBar)
{
searchBar.resignFirstResponder()
// Done editing: enable the other controls again.
controlContainerView.userInteractionEnabled = false
someButton.userInteractionEnabled = false
}
Upvotes: 0
Reputation: 689
You can create category for the UiView and override the touchesBegan meathod as follows.
It is working fine for me.And it is centralize solution for this problem.
#import "UIView+Keyboard.h"
@implementation UIView(Keyboard)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.window endEditing:true];
[super touchesBegan:touches withEvent:event];
}
@end
Upvotes: 3
Reputation: 31940
You can do this using the Storyboard in XCode 6 and above:
Add this to the header file of the class used by your ViewController:
@interface TimeDelayViewController : UIViewController <UITextFieldDelegate>
- (IBAction)dissmissKeyboardOnTap:(id)sender;
@end
Then add this to the implementation file of the same ViewController:
- (IBAction)dissmissKeyboardOnTap:(id)sender{
[[self view]endEditing:YES];
}
This will now be one of the 'Received Actions' for your storyboard scene (i.e. ViewController):
Now you need to hook up this action to the user gesture of touching off the keyboard.
Important - You need to convert the 'UIView' that's contained in your storyboard to a UIControl, so it can receive events. Select the view from your View Controller Scene hierarchy:
...and change its class:
Now drag from the small circle next to the 'received action' for your scene, onto an 'empty' part of your scene (actually you're dragging the 'Received Action' to the UIControl). You'll be shown a selection of events that you can hook up your action to:
Select the 'touch up inside' option. You've now hooked the IBAction you created to a user action of touching off the keyboard. When the user taps off the keyboard, it will now be hidden.
(NOTE: To hook the action to the event, you can also drag from the received action directly onto the UIControl in your View Controllers hierarchy. It's displayed as 'Control' in the hierarchy.)
Upvotes: 6
Reputation: 522
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.view.endEditing(true)
super.touchesBegan(touches, withEvent: event)
}
Upvotes: 0
Reputation: 487
just use this code in your .m file it will resign the textfield when user tap outside of the textfield.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[textfield resignFirstResponder];
}
Upvotes: 0
Reputation: 2020
One of the most easiest and shortest way is to add this code to your viewDidLoad
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self.view
action:@selector(endEditing:)]];
Upvotes: 2
Reputation: 2567
Check this, this would be the easiest way to do that,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];// this will do the trick
}
Or
This library will handle including scrollbar auto scrolling, tap space to hide the keyboard, etc...
https://github.com/michaeltyson/TPKeyboardAvoiding
Upvotes: 107
Reputation: 1693
This is a good generic solution:
Objective-C:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
Swift:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
Based on @icodebuster solution: https://stackoverflow.com/a/18756253/417652
Upvotes: 17