61

UPDATE:

I also tried implementing UITextViewDelegate delegate and then doing in my controller:

- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
    [textView resignFirstResponder];
    return YES;
}

I also set the delegate of the text view to be self (controller view instance).

Clicking the Done button still inserts just a new line :(


UPDATE:

What I have done so far. I have implemented a UITextFieldDelegate by my view controller.

I have connected the text view to the view controller via outlet.

Then I did:


self.myTextView.delegate = self;

And:

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

But when I click on Done button, it just adds a new line.

So I have a UITextView element on my scene and when a user taps it, keyboard appears and it can be edited.

However, I cannot dismiss the keyboard.

How can I add Done button to the keyboard so it can be dismissed?

GingerHead
  • 8,130
  • 15
  • 59
  • 93
Richard Knop
  • 81,041
  • 149
  • 392
  • 552
  • @joerick I tried your link. When I click on the Done button, it just inserts a new line. – Richard Knop Apr 09 '12 at 17:55
  • Show us what you've got so far; post the code you're using at the moment, and then we can see what you might be doing wrong. – joerick Apr 09 '12 at 17:57
  • @joerick Check my latest update (on top of my post). I have tried everything, your link (and others as well) and all answers posted on this page. Clicking Done still just adds a new line :( – Richard Knop Apr 09 '12 at 21:51

11 Answers11

128

thats quite simple :)

[textField setReturnKeyType:UIReturnKeyDone];

for dismissing the keyboard implement the <UITextFieldDelegate> protocol in your class, set

textfield.delegate = self;

and use

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [textField resignFirstResponder];
}

or

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}
iwasrobbed
  • 46,496
  • 21
  • 150
  • 195
Sebastian Flückiger
  • 5,525
  • 8
  • 33
  • 69
  • I did all that and clicking the Done button still just inserts a new line. Check my updated question. – Richard Knop Apr 09 '12 at 21:51
  • 1
    hi, you should be able to figure out what went wrong. i posted you code for a UITextField, and you copied it for your UITextView without changing it. use a `UITextField`, implement `` and use the code i provided you with :) a UITextView cant use the UITextFieldDelegate of course. however you can use the `` protocol if you really want to stick to the textview. more info: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextViewDelegate_Protocol/Reference/UITextViewDelegate.html – Sebastian Flückiger Apr 09 '12 at 22:35
  • Thanks. I have used UITextVieDelegate and it works. One question. Is it possible to allow multiple lines and also have a done button to dismiss the keyboard? I mean, is it possible to have both return and done buttons? – Richard Knop Apr 10 '12 at 19:35
  • have never tried it, but you could set an integer in your class, and every time someone enters a `\n` character increment the counter, and when you hit the maximum of lines you resign firstresponder – Sebastian Flückiger Apr 10 '12 at 22:00
  • textFieldShouldReturn must be implemented, not `or`, it is an `and` – ideawu Jan 14 '15 at 09:27
  • @ideawu `optional func textFieldShouldReturn(_ textField: UITextField) -> Bool`. it is optional. if not needed, dont implement it. – Sebastian Flückiger Jan 14 '15 at 11:38
  • @SebastianFlückiger if you don't implemtn textFieldShouldReturn and return YES, textFieldDidEndEditing will not get called. I am pretty sure. – ideawu Jan 14 '15 at 12:01
  • it's an optional function as per definition :) – Sebastian Flückiger Jan 15 '15 at 07:25
  • In swift this doesnt work self.textField.returnKeyType = UIReturnKeyType.done; – Return-1 Sep 15 '17 at 10:15
  • For me it's working with the only textFieldShouldReturn, no need for textFieldDidEndEditing. Writing in Swift 4.1 – Andrea Gorrieri Jun 04 '18 at 13:37
19

Add UIToolBar as custom view that will have Done button as UIBarButtonItem in it.

This is safer and cleaner way to add Done button to any Type of Keyboard. Create UIToolBar add Done Button to it and set inputAccessoryView of any UITextField or UITextView.

UIToolbar *ViewForDoneButtonOnKeyboard = [[UIToolbar alloc] init];
[ViewForDoneButtonOnKeyboard sizeToFit];
UIBarButtonItem *btnDoneOnKeyboard = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                               style:UIBarButtonItemStyleBordered target:self
                                                              action:@selector(doneBtnFromKeyboardClicked:)];
[ViewForDoneButtonOnKeyboard setItems:[NSArray arrayWithObjects:btnDoneOnKeyboard, nil]];

myTextField.inputAccessoryView = ViewForDoneButtonOnKeyboard;

IBAction For Done Button

 - (IBAction)doneBtnFromKeyboardClicked:(id)sender
  {
      NSLog(@"Done Button Clicked.");

      //Hide Keyboard by endEditing or Anything you want.
      [self.view endEditing:YES];
  }

SWIFT 3

var ViewForDoneButtonOnKeyboard = UIToolbar()
ViewForDoneButtonOnKeyboard.sizeToFit()
var btnDoneOnKeyboard = UIBarButtonItem(title: "Done", style: .bordered, target: self, action: #selector(self.doneBtnFromKeyboardClicked))
ViewForDoneButtonOnKeyboard.items = [btnDoneOnKeyboard]
myTextField.inputAccessoryView = ViewForDoneButtonOnKeyboard

Function

  @IBAction func doneBtnFromKeyboardClicked (sender: Any) {
     print("Done Button Clicked.")
    //Hide Keyboard by endEditing or Anything you want.
    self.view.endEditing(true)
  }
ViJay Avhad
  • 2,684
  • 22
  • 26
  • On Xcode 11.2, building for iOS 12, I get an autolayout crash unless I used `let ViewForDoneButtonOnKeyboard = UIToolbar(frame: CGRect(x: 0.0, y: 0.0, width: 500.0, height: 70))`. The `CGRect` is completely arbitrary but Xcode dumped out a line: ``, so providing a width seemed to fix this – Todd Nov 25 '19 at 11:20
18

Go into your storyboard, select your text field and under the Attributes Inspector there is an option that says "return key"...select "Done".

Then go into your ViewController and add:

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

Then go back to your text field, click outlets and link "Did end on exit" to dismissKeyboard action.

Mike Z
  • 4,121
  • 2
  • 31
  • 53
12

Swift version:

In Your ViewController:

textField.returnKeyType = UIReturnKeyType.Done
textField.delegate = self

After your ViewController

extension MyViewController: UITextFieldDelegate {        
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
1

Set the 'Return Key' option under the text field option in the inspector for your text field. Then right click on the text field and while holding CTRL select 'Did End On Exit' and drag this into your view controllers file. This will create an IBAction method. Give the method a name and then enter the following values:

[textField becomeFirstResponder];
[textField resignFirstResponder];

Your method should look like this:

- (IBAction)methodName:(id)sender;
{
    [sender becomeFirstResponder];
    [sender resignFirstResponder];
}
kjhughes
  • 106,133
  • 27
  • 181
  • 240
Garreth Golding
  • 985
  • 2
  • 11
  • 19
1

Ok, so I too have been struggling with this very issue. Currently I am accessing a UITextView in a UITableViewCell (via Tags). Because I am using prototype cells I cannot use IBActions nor IBOutlets like everyone suggests. Instead, I am using;

-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text

This will then provide me with the text each time the user hits a button. My solution then, was to get the ascii character for new line; "/n". If that is the text that was entered, I would resign the first responder. For example;

// If the text length is 0 then the user is deleting something, so only check the ascii character if there is text to check
if (text.length != 0) {
    // Get the Ascii character
    int asciiCode = [text characterAtIndex:0];
    // If the ascii code is /n or new line, then resign first responder
    if (asciiCode == 10) {
        [alertTextView resignFirstResponder];
        [DeviceTextView resignFirstResponder];
    }
}

Not sure if anyone else will need this hacky solution but I figured I'd put it out there in case someone needs it!

Donato Perconti
  • 814
  • 2
  • 11
  • 28
1

This is best way to add Done Button on keyboard

textField.returnKeyType = UIReturnKeyDone;
DURGESH
  • 2,373
  • 1
  • 15
  • 13
0

The following is my approach, in Swift 3. When the doneBtn clicked, let it send .editingDidEndOnExit event. I use this event to handle focus problem between multiple textFields.

// My customized UITextField
class MyTextField: UITextField {

    override func awakeFromNib() {
        super.awakeFromNib()

        // Add toolBar when keyboardType in this set. 
        let set : [UIKeyboardType] = [.numberPad, .phonePad]
        if (set.contains(self.keyboardType) ) {
            self.addDoneToolbar()
        }
    }

    // Add a toolbar with a `Done` button
    func addDoneToolbar() {

        let toolbar = UIToolbar()
        let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let doneBtn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(onToolBarDone))

        toolbar.items = [space, doneBtn]
        toolbar.sizeToFit()

        self.inputAccessoryView = toolbar
    }

    @objc func onToolBarDone() {
        // I use `editingDidEndOnExit` to simulate the `Done` behavior 
        // on the original keyboard.
        self.sendActions(for: .editingDidEndOnExit)
    }
}
AechoLiu
  • 17,522
  • 9
  • 100
  • 118
0

For Swift 5 and above versions

    extension UITextField {

   func addDoneButtonOnKeyboard() {
       let keyboardToolbar = UIToolbar()
       keyboardToolbar.sizeToFit()
       let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
           target: nil, action: nil)
       let doneButton = UIBarButtonItem(barButtonSystemItem: .done,
           target: self, action: #selector(resignFirstResponder))
       keyboardToolbar.items = [flexibleSpace, doneButton]
       self.inputAccessoryView = keyboardToolbar
   }
}
extension UITextView{
    func addDoneButtonKeyboard(){
        let keyboardToolbar = UIToolbar()
        keyboardToolbar.sizeToFit()
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                            target: nil, action: nil)
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done,
                                         target: self, action: #selector(resignFirstResponder))
        keyboardToolbar.items = [flexibleSpace, doneButton]
        self.inputAccessoryView = keyboardToolbar
    }
}
0

iOS 14+ Solution

Edit: Worked for me on iOS 15 but not on iOS 16

This will place a "done" button in the center of the field above the keybaord.

TextField("MyField")
 .toolbar{
    Button("Done"){
    //Close keyboard
    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }.tint(.blue)
  }
Some guy
  • 51
  • 9
-2

In Interface Builder on the properties of the textView you can set the return button type to Done.

Then you need to check for when the Return button is pressed using

  - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text

Check if the text == "/n" then dismiss the keyboard by resigning first responder on your textView.

Ryan Poolos
  • 18,421
  • 4
  • 65
  • 98