ChatGPT解决这个技术问题 Extra ChatGPT

How do you dismiss the keyboard when editing a UITextField

I know that I need to tell my UITextField to resign first responder when I want to dismis the keyboard, but I'm not sure how to know when the user has pressed the "Done" key on the keyboard. Is there a notification I can watch for?

[self.view endEditing:YES]; in touches began delegate is the best solution

I
Irfan

I set the delegate of the UITextField to my ViewController class.

In that class I implemented this method as following:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return NO;
}

See the example above... wire that using IntefaceBuilder to the action on whatever you're using as your controller... whenever the user dismisses the text entry system (presses done), this will be invoked...
Either of these will work - the text field sends its action when the user hits the Return ("Done", whatever) key, and also sends its delegate -textFieldShouldReturn:.
BTW - this also works for a UISearchBar. For example, my code I had a member IBOutlet searchBarTusb; When my 'return key' (UIReturnKeySearch) was clicked, -(void) searchBarSearchButtonClicked:, I put the statement [searchBarTusb resignFirstResponder]; Also note, the 'return key' was set in the NIB using Interface Builder.
Why return NO instead of YES?
@IulianOnofrei The default behavior of the return button is to add a line return and keep the keyboard onscreen. By returning NO you avoid adding a line return to the text.
t
teedyay

If you connect the DidEndOnExit event of the text field to an action (IBAction) in InterfaceBuilder, it will be messaged when the user dismisses the keyboard (with the return key) and the sender will be a reference to the UITextField that fired the event.

For example:

-(IBAction)userDoneEnteringText:(id)sender
{
    UITextField theField = (UITextField*)sender;
    // do whatever you want with this text field
}

Then, in InterfaceBuilder, link the DidEndOnExit event of the text field to this action on your controller (or whatever you're using to link events from the UI). Whenever the user enters text and dismisses the text field, the controller will be sent this message.


The only event that seems like it might work is textFieldDidEndEditing, which states it's only sent after the UITextField resigns first responder status. How do I know when I need to resign first responder status?
I'm sorry about the terminology... it's not an actual notification (event)... I'm going to edit my answer with a quick example and explanation, so see that :)
To clarify this answer, the textField sends the "Did End On Exit" event when you hit the return key, so that's the one you need to link to your controller. I think this method is easier than the one I outlined above.
could you edit this answer so that it mentions WHICH event to wire, please? This is obviously nicer than setting the delegate.
Want to upvote this answer, but can't until it mentions the DidEndOnExit event. Someone with edit privileges please make the change if the OP won't?
H
Hugo

You can also create a method in your controller

 -(IBAction)editingEnded:(id)sender{
    [sender resignFirstResponder]; 
}

and then in Connection Inspector in IB connect Event "Did End On Exit" to it.


This is almost incorrect, or at least it misses the point. By subscribing to the DidEndOnExit event, you do not need to call resignFirstResponder. You can test this by putting a symbolic breakpoint on [UIResponder resignFirstResponder]. Note that even if if you don't call resignFirstResponder, it still gets called by the system. This is explained in Matt Neuburg's excellent book(s): apeth.com/iOSBook/…
R
Rob

kubi, thanks. Your code worked. Just to be explicit (for newbies like) as you say you have to set the UITextField's delegate to be equal to the ViewController in which the text field resides. You can do this wherever you please. I chose the viewDidLoad method.

- (void)viewDidLoad 
{
    // sets the textField delegates to equal this viewController ... this allows for the keyboard to disappear after pressing done
    daTextField.delegate = self;
}

If you added text field to your storyboard or NIB, you can set the text field's delegate there, too. You don't have to do this programmatically, as demonstrated above. Either approach works fine.
m
matt

Here is a trick for getting automatic keyboard dismissal behavior with no code at all. In the nib, edit the First Responder proxy object in the Identity inspector, adding a new first responder action; let's call it dummy:. Now hook the Did End on Exit event of the text field to the dummy: action of the First Responder proxy object. That's it! Since the text field's Did End on Exit event now has an action–target pair, the text field automatically dismisses its keyboard when the user taps Return; and since there is no penalty for not finding a handler for a message sent up the responder chain, the app doesn't crash even though there is no implementation of dummy: anywhere.


@matt I discovered that IF I add an unwind segue AND connect the didEndOnExit event THEN the unwind segue will be triggered upon pressing Return. Without the event connection the segue is not triggered. Great but Huh? Any remarks? BTW: I have your Swift (finished) and iOS10 (on chap 6) books. They have helped me tremendously!
@Verticon the question and answer has nothing to do with segues, so I don't understand the issue... :( this is purely about keyboard dismissal
@matt Sorry, man. I was piggy backing because 1) I came upon this thread while I was dealing with how to handle the UITextField's return key; and 2) it was a chance to interact with you (thx for da books). There is no "issue". Just a lack of understanding on my part about why/how it works the way it does.
@Verticon I apologize for not being able to help. Feel free to formulate a new question with more info (demo project?) and blip me, if I can be useful.
S
Safin Ahmed

In Swift you can write an IBAction in the Controller and set the Did End On Exit event of the text field to that action

@IBAction func returnPressed(sender: UITextField) {
    self.view.endEditing(true)
}

A
Alex Zavatone

Just add

[textField endEditing:YES];

where you want to disable keyboard and display the picker view.


B
Bùi Đức Khánh

Swift 4.2 and It will work 100%

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        self.textField.delegate = self

    }

    // hide key board when the user touches outside keyboard

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

    // user presses return key

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

}

I appreciated the fact that this answer also taught me how to dismiss the keyboard when the user touches outside it.
M
Metalhead1247

You can also use

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

   [self.yourTextField resignFirstResponder];

  }

Best one if You have many Uitextfields :

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

R
Ryan Bourne

Here's what I had to do to get it to work, and I think is necessary for anyone with a Number Pad for a keyboard (or any other ones without a done button:

I changed the UIView in the ViewController to a UIControl. I created a function called -(IBAction)backgroundIsTapped:(id)sender

This was also defined in the .h file.

After this, I linked to to the 'touch down' bit for the ViewController in Interface Builder.

In the 'background is tapped' function, I put this:

    [answerField resignFirstResponder];

Just remember to change 'answerField' to the name of the UITextField you want to remove the keyboard from (obviously make sure your UITextField is defined like below:)

    IBOutlet UITextField * <nameoftextfieldhere>;

I know this topic probably died a long time ago... but I'm hoping this will help someone, somewhere!


..but it does not work so well if the user taps another control.
R
Rob

You will notice that the method "textFieldShouldReturn" provides the text-field object that has hit the DONE key. If you set the TAG you can switch on that text field. Or you can track and compare the object's pointer with some member value stored by its creator.

My approach is like this for a self-study:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    bool fDidResign = [textField resignFirstResponder];

    NSLog(@"%s: did %resign the keyboard", __FUNCTION__, fDidResign ? @"" : @"not ");

    return fDidResign;
}

Meanwhile, I put the "validation" test that denies the resignation follows. It is only for illustration, so if the user types NO! into the field, it will not dismiss. The behavior was as I wanted, but the sequence of output was not as I expected.

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    NSLog(@"%s", __FUNCTION__);

    if( [[textField text] isEqualToString:@"NO!"] ) {
        NSLog(@"%@", textField.text);
        return NO;
    } else {
        return YES;
    }
}

Following is my NSLog output for this denial followed by the acceptance. You will notice that I am returning the result of the resign, but I expected it to return FALSE to me to report back to the caller?! Other than that, it has the necessary behavior.

13.313 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]
13.320 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldEndEditing:]
13.327 StudyKbd[109:207] NO!
13.333 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]: did resign the keyboard
59.891 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]
59.897 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldEndEditing:]
59.917 StudyKbd[109:207] -[StudyKbdViewController doneEditText]: NO
59.928 StudyKbd[109:207] -[StudyKbdViewController textFieldShouldReturn:]: did resign the keyboard

can u explain ..if i return NO or YES in both case same things happen so what the need of returning yes in textFieldShouldReturn delegate method
M
Moose

Here is a quite clean way to end edition with the Return Key or a touch in the background.

In Interface builder, embed your fields in a view of class UIFormView

What does this class :

Automatically attach itself as fields delegate ( Either awaked from nib, or added manually )

Keep a reference on the current edited field

Dismiss the keyboard on return or touch in the background

Here is the code :

Interface

#import <UIKit/UIKit.h>

@interface UIFormView : UIView<UITextFieldDelegate>

-(BOOL)textFieldValueIsValid:(UITextField*)textField;
-(void)endEdit;

@end

Implementation

#import "UIFormView.h"

@implementation UIFormView
{
    UITextField* currentEditingTextField;
}

// Automatically register fields

-(void)addSubview:(UIView *)view
{
    [super addSubview:view];
    if ([view isKindOfClass:[UITextField class]]) {
        if ( ![(UITextField*)view delegate] ) [(UITextField*)view setDelegate:self];
    }
}

// UITextField Protocol

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    currentEditingTextField = textField;
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    currentEditingTextField = NULL;
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self endEdit];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if ([self textFieldValueIsValid:textField]) {
        [self endEdit];
        return YES;
    } else {
        return NO;
    }
}

// Own functions

-(void)endEdit
{
    if (currentEditingTextField) {
        [currentEditingTextField endEditing:YES];
        currentEditingTextField = NULL;
    }
}


// Override this in your subclass to handle eventual values that may prevent validation.

-(BOOL)textFieldValueIsValid:(UITextField*)textField
{
    return YES;
}

@end

By subclassing the form and overriding the textFieldValueIsValid: method, you can avoid end of edition if the value is not correct for the given field.

If a field has a delegate set in Interface Builder, then the form does not change it. I don't see many reasons to set a different delegate to a particular field, but why not…

There is many ways to improve this form view class - Attach a delegate, do some layout, handle when the keyboards covers a field ( using the currentEditingTextField frame ), automatically start edition for the next field, ...

I personally keep it in my framework, and always subclass it to add features, it is quite often useful "as-is".

I hope it will helps. Cheers all


Helpful class. One small point, you shouldn't prefix your own classes with "UI". In objective-c you should use your own prefix ("TL"?), in Swift, don't use anything.
Thanks @kubi. That's right. It is MF in my framework, like MooseFactory ;)
A
Abhimanyu Rathore

if you want all editing of in a UIViewController you can use.

[[self view]endEditing:YES];

and if you want dismiss a perticular UITextField keyboard hide then use.

1.add delegate in your viewcontroller.h

<UITextFieldDelegate>

make delegation unable to your textfield . self.yourTextField.delegate = self; add this method in to your viewcontroller. -(BOOL)textFieldShouldEndEditing:(UITextField *)textField{ [textField resignFirstResponder]; return YES;}


T
Tanjima Kothiya

Programmatically set the delegate of the UITextField in swift 3

Implement UITextFieldDelegate in your ViewController.Swift file (e.g class ViewController: UIViewController, UITextFieldDelegate { )

 lazy var firstNameTF: UITextField = {

    let firstname = UITextField()
    firstname.placeholder = "FirstName"
    firstname.frame = CGRect(x:38, y: 100, width: 244, height: 30)
    firstname.textAlignment = .center
    firstname.borderStyle = UITextBorderStyle.roundedRect
    firstname.keyboardType = UIKeyboardType.default
    firstname.delegate = self
    return firstname
}()

lazy var lastNameTF: UITextField = {

    let lastname = UITextField()
    lastname.placeholder = "LastName"
    lastname.frame = CGRect(x:38, y: 150, width: 244, height: 30)
    lastname.textAlignment = .center
    lastname.borderStyle = UITextBorderStyle.roundedRect
    lastname.keyboardType = UIKeyboardType.default
    lastname.delegate = self
    return lastname
}()

lazy var emailIdTF: UITextField = {

    let emailid = UITextField()
    emailid.placeholder = "EmailId"
    emailid.frame = CGRect(x:38, y: 200, width: 244, height: 30)
    emailid.textAlignment = .center
    emailid.borderStyle = UITextBorderStyle.roundedRect
    emailid.keyboardType = UIKeyboardType.default
    emailid.delegate = self
    return emailid
}()

// Mark:- handling delegate textField..

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

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

    if textField == firstNameTF {

        lastNameTF.becomeFirstResponder()
    }

    else if textField == lastNameTF {

        emailIdTF.becomeFirstResponder()
    }
    else {
        view.emailIdTF(true)
    }
    return true
}

p
pooja_chaudhary

Create a function hidekeyboard and link it to the textfield in the .xib file and select DidEndOnExit

-(IBAction)Hidekeyboard    
{    
      textfield_name.resignFirstResponder;    
}  

k
kubi

If you have created the view using Interface Builder, Use the following Just create a method,

-(IBAction)dismissKeyboard:(id)sender
{
[sender resignFirstResponder];
}

Just right click the text field in the view , and set the event as Did End on Exit, and wire it to the method "dismissKeyboard".

The best guide for beginners is "Head First iPhone and iPad Development, 2nd Edition"


V
Vineesh TP

try this

- (BOOL) textView: (UITextView*) textView shouldChangeTextInRange: (NSRange) range replacementText: (NSString*) text
{
    if ([text isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }
    return YES;
}

j
jake
//====================================================
//                  textFieldShouldReturn:
//====================================================
-(BOOL) textFieldShouldReturn:(UITextField*) textField { 
    [textField resignFirstResponder];
    if(textField.returnKeyType != UIReturnKeyDone){
        [[textField.superview viewWithTag: self.nextTextField] becomeFirstResponder];
    }
    return YES;
}

B
Burf2000

Anyone looking for Swift 3

1) Make sure your UITextField's Delegate is wired to your ViewController in the Storyboard

2) Implement UITextFieldDelegate in your ViewController.Swift file (e.g class ViewController: UIViewController, UITextFieldDelegate { )

3) Use the delegate method below

func textFieldShouldReturn(textField: UITextField) -> Bool { 
   textField.resignFirstResponder()  
return false }

P
Prakhar Prakash Bhardwaj

This is how I dismiss the keyboard in Swift 4.2 and it works for me:

    override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: 
    #selector(dismissKeyboard))

    view.addGestureRecognizer(tap)
    }

    @objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    numberField.resignFirstResponder()
    }

A
Artem Deviatov

Swift 3, iOS 9+

@IBAction private func noteFieldDidEndOnExit(_ sender: UITextField) {}

UPD: It still works fine for me. I think guy that devoted this answer just didn't understand that he needs to bind this action to the UITextField at the storyboard.


Q
Qantas 94 Heavy
textField.returnKeyType = UIReturnKeyDone;