52

today I tried to run my code on my iPod (iOS 6.1.3) and I found something interesting here...

first, when I tap on textfield the keyboard shows up but it won't hide when I tap somewhere else outside textfield.

so I decided to Googling and found this solution :

_fieldEmail.delegate = self;
_fieldEmail.returnKeyType = UIReturnKeyDone;

_fieldPassword.delegate = self;
_fieldPassword.returnKeyType = UIReturnKeyDone;

_fieldRegisterName.delegate = self;
_fieldRegisterName.returnKeyType = UIReturnKeyDone;

_fieldRegisterEmail.delegate = self;
_fieldRegisterEmail.returnKeyType = UIReturnKeyDone;

_fieldRegisterPassword.delegate = self;
_fieldRegisterPassword.returnKeyType = UIReturnKeyDone;

it works... it gives a 'DONE' button on the bottom of keyboard and now the keyboard can be hidden by pressing it.

but I have 2 problems here :

  1. the keyboard only hide when 'DONE' button is tapped. not by tapping other area outside text field. I don't know if this normal on iOS world, but usually I see lot of apps don't act like this.
  2. is there any way to loop this process so I don't have manually add that delegate one by one of all textfield that I have? how to do that?

that's all I need to know

icodebuster
  • 8,780
  • 7
  • 59
  • 63
Saint Robson
  • 5,211
  • 15
  • 63
  • 106
  • There are some good answers [here][1] [1]: http://stackoverflow.com/questions/7794959/how-to-resign-first-responder-from-text-field-when-user-tap-elsewhere – ICL1901 Sep 12 '13 at 05:48
  • possible duplicate of [iphone, dismiss keyboard when touching outside of textfield](http://stackoverflow.com/questions/5306240/iphone-dismiss-keyboard-when-touching-outside-of-textfield) – icodebuster Sep 12 '13 at 05:54

14 Answers14

83

The below code will work on all the components in the UIView for all the UITextField

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UIView * txt in self.view.subviews){
        if ([txt isKindOfClass:[UITextField class]] && [txt isFirstResponder]) {
            [txt resignFirstResponder];
        }
    }
}

OR

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];    
}
icodebuster
  • 8,780
  • 7
  • 59
  • 63
30
  1. Simply add an UITapGestureRecogniser to your view that will lead to calling resignFirstResponder

In viewDidLoad :

UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] 
                                   initWithTarget:self
                                   action:@selector(hideKeyBoard)];

[self.view addGestureRecognizer:tapGesture];

And then :

-(void)hideKeyBoard {
       [yourTextField resignFirstResponder];
}

2.You could subclass UITextField but unless you have 1000 textFields it is ok to do like you currently do.

Piyush
  • 173
  • 8
LudoZik
  • 917
  • 1
  • 7
  • 20
  • I did exactly what you said : -(void)dismissKeyboard { [UITextField fieldEmail : hideKeyBoard]; } and here's what Xcode says : use of undeclared identifier 'hideKeyBoard', where to declare hideKeyBoard anyway? – Saint Robson Sep 12 '13 at 05:58
  • Sorry, I made a mistake in my anwser ; I edited it with 'resignFirstResponder' – LudoZik Sep 12 '13 at 06:38
  • 2
    This will not work if you have other controls on your screen that need to be tapped, such as segues on table cells. Is there a way to only invoke the tap gesture when the keyboard is shown? – mreynol Nov 08 '14 at 15:32
  • Thanks I used the selector but in combination with [self.view endEditing:YES]; in -(void)hideKeyBoard { method. It works. – Nicola Dec 26 '15 at 09:01
19

This is regards to Swift programming for Xcode 6.0.1

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
    tapRecognizer.numberOfTapsRequired = 1
    self.view.addGestureRecognizer(tapRecognizer)
}

func handleSingleTap(recognizer: UITapGestureRecognizer) {
    self.view.endEditing(true)
}
He Yifei 何一非
  • 2,292
  • 3
  • 31
  • 66
Vinod Joshi
  • 7,094
  • 46
  • 49
  • This is great, except in latest version is throws an error on the selector. Replace with this: `let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap(_:)))` – Wade Jun 06 '16 at 06:19
  • Now it's sufficient: let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap)) – Colibri Aug 25 '17 at 12:42
7

Use Either

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];

and code of method

-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
    [self.TextFiledName resignFirstResponder];

}

OR _ And The best Other option is

Just add

  [self.view endEditing:YES];

And key board will hide when you tapped anywhere from view:)

iPatel
  • 41,165
  • 13
  • 109
  • 131
7

Dismissing the keyboard

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
        [self.view endEditing:YES];
        [super touchesBegan:touches withEvent:event];
    }
Soner Gönül
  • 91,172
  • 101
  • 184
  • 324
3

What I usually do is call

[field resignFirstResponder]; 

from an invisible button over the view. I'm sure theres a nicer way to do it. It's been a while since I've done this in an app.

Sam Jarman
  • 7,025
  • 14
  • 49
  • 98
  • where to put that code? I tried like this : _fieldEmail.delegate = self; _fieldEmail.returnKeyType = UIReturnKeyDone; [_fieldEmail resignFirstResponder]; but still it won't change the behaviour – Saint Robson Sep 12 '13 at 05:47
3

Simple,

Use IQKeyboardManager and put this line of code in AppDelegate.m

[[IQKeyboardManager sharedManager] setShouldResignOnTouchOutside:YES];
itsji10dra
  • 4,550
  • 3
  • 36
  • 55
Sandip Patel - SM
  • 3,143
  • 25
  • 27
1

Here's how I do it:

In the myView's .h file:

@property (strong) UITextField * savedTextField;

In the myView's .m file:

@implementation myView

@synthesize savedTextField;

In the myView's init routine:

[self setSavedTextField: nil];

In the myView's textField delegate area I save the id of whichever textField is currently activating:

- (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
   {
   [self setSavedTextField: textField];
   .
   .
   .
   return( YES );
   }

And in the myView's routine that routes all the traffic for the other controls when they are accessed, I have code that looks to see if a textField was active and, if one was, it calls on it to resign its FirstResponder status and then drops a nil into the savedTextField property:

- (void) handleCtrlEvents: (UIControl *) aCtrl
  {
  if ( [self savedTextField] != nil )
     {
     [[self savedTextField] resignFirstResponder];
     [self setSavedTextField: nil];
     }
  .
  .
  .
  }

This works cleanly for me.

Gallymon
  • 1,527
  • 1
  • 11
  • 21
  • I tried icodebuster's suggestion and it works better than my suggestion because it causes an appropriate resignFirstResponder to occur when the user taps in the view anywhere and you do not need to keep track of anything. Sweet. – Gallymon Nov 08 '13 at 23:06
  • perfect answer. tnx. – Sathya Baman Dec 08 '16 at 12:10
1

I ran into the exact same problem. Usually what you want is, that wherever you click inside your App (which is displayed in your main / current UIView) but not on the keyboard to close it. After searching the web for a smart solution and testing several, I think it is the best to extend/subclass/implement the UIGestureRecognizerDelegate

Since many controls such as UITableView etc. can respond to gestures (select, scrolling etc.) and if you simply add a UITapGestureRecognizer to the whole (main-)ViewController's view to close the keyboard, the user experience is not the best, since the user needs to tap twice if he didn't intend to close the keyboard but e.g. select a row from a UITableView inside the App's current "main" View.

Since I am quite new to the whole iOS and swift thing and swift code examples are rare, here's my full keyboard control snipped:

class ViewController: UIViewController, UIGestureRecognizerDelegate {

override func viewDidLoad(){
     self.initializeCloseKeyboardTap()
}

func initializeCloseKeyboardTap() {

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardOpen:", name: UIKeyboardDidShowNotification, object: nil)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardClose:", name: UIKeyboardDidHideNotification, object: nil)
    let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleOnTapAnywhereButKeyboard:")
    tapRecognizer.delegate = self //delegate event notifications to this class
    self.view.addGestureRecognizer(tapRecognizer)

}


func onKeyboardClose(notification: NSNotification) {
    println("keyboardClosed")
}

func onKeyboardOpen(notification: NSNotification) {
    println("keyboardOpen")
}

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    self.view.endEditing(true)
    return false
}

you can nest it inside the ViewController and call initiallizeCloseKeyboardTa() in viewDidLoad implementation... It also implements a norfication observer to receive events as soon as the keyboard (finished to be) opened or closed via NSNotificationCenter UIKeyboardDidShowNotification and UIKeyboardDidHideNotification

Hope that save's other people some time :-)

  • I applied this to my textField and it worked great. It dismisses the keyboard if you tap anywhere outside of the textField. One problem... it also dismisses the keyboard if you tap on the textField itself. How do I prevent this? – peacetype Oct 15 '15 at 22:34
1

|*| Dismissing the UITextField’s Keyboard : override the method touchesBegan:withEvent: for the ViewController

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
    view.endEditing(true)
    super.touchesBegan(touches, withEvent: event)
}

|OR|

override func viewDidLoad()
{
    super.viewDidLoad()
// For tapping outside text box
    self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
}

// For tapping outside text box
func DismisKeyPadFnc()
{
    view.endEditing(true)
}

|*| Dismissing the UITextField’s Keyboard on induvidual textbox :

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet var NamTxtBoxVid: UITextField!

    override func viewDidLoad()
    {
        super.viewDidLoad()

    // For hitting return key
        NamTxtBoxVid.delegate = self

    // For tapping outside text box
        self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
    }

/* For hitting return key */
    func textFieldShouldReturn(NamTxtBoxPsgVid: UITextField) -> Bool
    {
        NamTxtBoxPsgVid.resignFirstResponder()
        return true
    }

/* For tapping outside text box */
    func DismisKeyPadFnc()
    {
        view.endEditing(true)
    }
}


|*| Implementing Next button Click :
1) You will be needing to set the tags in the incremental sequence of the textfields in xib/Storyboard or in code.
2) Set the delegate for each of the textfields.
3) Then paste the following code in your view controller to have the desired effect:

func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
{
    let NxtTxtBoxTagVal : Int = TxtBoxPsgVar.tag + 1

    let NxtTxtBoxVal: UIResponder? = TxtBoxPsgVar.superview?.superview?.viewWithTag(NxtTxtBoxTagVal)

    if let TxtBoxVal = NxtTxtBoxVal
    {
        // Found next responder, so set it.
        TxtBoxVal.becomeFirstResponder()
    }
    else
    {
        // Not found, so remove keyboard.
        TxtBoxPsgVar.resignFirstResponder()
    }
    return true
}
Sujay U N
  • 3,942
  • 6
  • 39
  • 65
0

I think

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

is convenient but not the best solution. and the TapGestureRecongnizer is better but hard to use,you have to set delegates and add and remove the Recongnizer. So I wrote a simple subclass which can be easily used:

class TapHideTextField: UITextField {
override func awakeFromNib() {
    super.awakeFromNib()
    tapGr = UITapGestureRecognizer(target: self, action:"tap")
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBeginEditing", name:UITextFieldTextDidBeginEditingNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "didEndEditing", name:UITextFieldTextDidEndEditingNotification, object: nil)

}

deinit{
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

var tapGr:UITapGestureRecognizer!
func tap(){
    self.endEditing(true)
}

func didBeginEditing(){
    self.superview!.addGestureRecognizer(tapGr)
}


func didEndEditing(){
    self.superview!.removeGestureRecognizer(tapGr)
}

}

you should concern about the superview and the cancelTouchesInView property.

or in GitHub:https://github.com/lilidan/TapHideText/blob/master/TapHideTextField.swift

cy SG
  • 31
  • 2
0

If you're using scroll view (or table view) controller, add these lines there:

    override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        view.endEditing(true)
    }
iOS Developer
  • 3,393
  • 2
  • 38
  • 56
0

I prefer IQKeyboardManager. You can simply handle keyboard in any state. To active IQKeyboard just add one line in AppDelegate and to dismiss keyboard on outside touch add code as below,

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  IQKeyboardManager.shared.enable = true
  IQKeyboardManager.shared.shouldResignOnTouchOutside = true

  return true
}
Komal Goyani
  • 591
  • 2
  • 18
-1
-(void) textFieldDidBeginEditing: (UITextField *) textField{
     [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(DismissKeyboard:)]];
}

-(void) DismissKeyboard:(UITapGestureRecognizer *) sender{
    [self.view endEditing:YES];
    [self.view removeGestureRecognizer:sender];
}
itsji10dra
  • 4,550
  • 3
  • 36
  • 55
jaya raj
  • 322
  • 3
  • 12