How to Dismiss the Keyboard when using a UITextView

Tue, Oct 14

Oddly this was more tricky then I would have thought … perhaps for a veteran Cocoa developer this would have been obvious, but for the rest of us struggling to get rid of the keyboard on a UITextView here is the secret sauce …

The short answer is to send the UITextViewController the “resignFirstResponder” message … the trick however is when to send the message. In my case, and I assume it would be the same for others, is to listen for any changes to the text in the UITextView and if the carridge return character ‘\n’ is detected then send the “resignFirstResponder” message to the UITextView.

Step 1. The first step is to make sure that you declare support for the UITextViewDelegate protocol. This is done in your header file, as example here is the header called EditorController.h:

1
2
3
4
5
6
7
@interface EditorController : UIViewController  {
  UITextView *messageTextView;
}
 
@property (nonatomic, retain) UITextView *messageTextView;
 
@end

Step 2. Next you will need to register the controller as the UITextView’s delegate. Continuing from the example above, here is how I have initialize the UITextView with EditorController as the delegate …

1
2
3
4
5
6
7
8
9
10
11
- (id) init {
    if (self = [super init]) {
        // define the area and location for the UITextView
        CGRect tfFrame = CGRectMake(10, 10, 300, 100);
        messageTextView = [[UITextView alloc] initWithFrame:tfFrame];
        // make sure that it is editable
        messageTextView.editable = YES;
 
        // add the controller as the delegate
        messageTextView.delegate = self;
    }

Step 3. And now the final piece of the puzzle is to take action in response to the “shouldCahngeTextInRange” message as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range 
  replacementText:(NSString *)text
{
    // Any new character added is passed in as the "text" parameter
    if ([text isEqualToString:@"\n"]) {
        // Be sure to test for equality using the "isEqualToString" message
        [textView resignFirstResponder];
 
        // Return FALSE so that the final '\n' character doesn't get added
        return FALSE;
    }
    // For any other character return TRUE so that the text gets added to the view
    return TRUE;
}

35 comments

since reading icodeblog.com I add this code the .m controller

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

by Bug on Oct 18, 2008. #

Thanks for the feedback. Unfortunately the delegate ‘textFieldShouldReturn:’ is not available for UITextView. You can only use it for UITextField. I wish it were … it would make UITextView easier to use!

by Rodney Aiglstorfer on Oct 18, 2008. #

thanks for suggestion but it will work till we are not pressing return so only one line can be added at a time. It will not work while we want to add 5-6 line in text view. so what is the solution for multi line entry?

by Jaydev gohil on Nov 6, 2008. #

Your point is correct. If you need to be able to add ‘\n’ characters then you will need to add a Cancel/Done button somewhere on your UI. I typically use the UIButtonBarItem class to create buttons for the left and right sides of the Nav Bar. I only add them when the text view becomes firstResponder.

by Rodney Aiglstorfer on Nov 6, 2008. #

thanks for reply. can you provide me the sample code for the UIButtonBarItem class to create button for left and right of Nav Bar and to add them when text view become first responder.

by Jaydev Gohil on Nov 6, 2008. #

Hi, thanks for the tutorial. I am using the same method to see how many rows are in a textView. If the user presses return then the ‘\n’ is sent and it puts the textView on the next row however, if the text is wrapped it moves to the next line without sending a ‘\n’. You know of any way I can detect when that happens?

by Sean on Jan 4, 2009. #

That is a little more of a challenge. Offhand I’d suggest that you listen for keystrokes, and upon each stroke, calculate the pixel length of the string. Using this information you could determine how many lines are rendered (wrapped or otherwise).

For more information of calculating String width and height take a look at this tutorial …

http://iphonedevelopertips.com/cocoa/how-to-compute-string-sizes.html

by Rodney Aiglstorfer on Jan 4, 2009. #

Hi,

I ve been searching all kinds of blog for this keypad dismissal (It comes as a welcome sign to see but to get rid of it…….. hmmm breaks ones neck). In my case i have 3 textfields and one of them i enter numbers. For the number keypad or the phone keypad there is no DONE button! How to get rid of it. For text entry the code given in iphone101 and (#Bug) does work but for this number case i am stuck. In one blog i read that i should add a button and assign it to the TextField “DidEndOnExit” event. I did that but once i try to see which is the first responder it does not work….. Here is the code

//This works in a stupid fashion
-(IBAction) getRidofResponder : (id) sender{
[FirstTextField resignFirstResponder];
[SecondTextField resignFirstResponder];
[ThirdTextFieldPhoneNumber resignFirstResponder];
}

//This does not work
-(IBAction) getRidofResponder : (id) sender{

if([FirstTextField isFirstResponder])
[FirstTextField resignFirstResponder];
else if([SecondTextField isFirstResponder])
[SecondTextField resignFirstResponder];
else if([ThirdTextFieldPhoneNumber isFirstResponder])
[ThirdTextFieldPhoneNumber resignFirstResponder]
}

Any help on this????? Is there another better way of solving this issue?
Thanks

by maxfiresolutions on Feb 6, 2009. #

Set up notification for the key press and then just check to see if it is a \n and resign.

In viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(textViewKeyPressed:) name: UITextViewTextDidChangeNotification object: nil];

and then

-(void) textViewKeyPressed: (NSNotification*) notification {

if ([[[notification object] text] hasSuffix:@”\n”])
{
[[notification object] resignFirstResponder];
}

by Todd on Sep 7, 2012. #

@maxfiresolutions I am surprised that the second example didn’t work for you. I’ve not had a reason in my applications to test for isFirstResponder so I can’t say for sure that you are using it correctly.

One thing you could do is register a delegate for the event that is generated when the UITextField becomes FirstResponder and associate the “active” TextView with some instance variable. That way when you need to resignFirstResponder you don’t need to test … just use the instance variable.

Another place to look is at tapping into the NSNotificationCenter. I suspect there is an existing event you can register to receive in just such a case.

by Rodney Aiglstorfer on Feb 6, 2009. #

very neat. Solved my problem instantly. Thanks.

by dogan berktas on Jun 13, 2009. #

ah this is great – worked for me, ‘cept I skipped the middle chunk of code (delegate part) and provided the connection in dreamweaver, I mean Interface Builder (referencing outlet of files owner delegate connected to the text view).

Thank You for this excellent post!

SF

by SteadyFwd on Jun 29, 2009. #

This never worked for me. I declared the hosting view controller to be the text view’s delegate, and added the method as shown. This method never gets called. Perhaps you assumed some other step that I am not aware of.

by Hal on Jul 8, 2009. #

Be sure to include the protocol after the UIViewController subclass interface header file.

by marcoyukon on Sep 28, 2009. #

Be sure to include the UITextViewDelegate protocol after the UIViewController subclass interface header file.

by marcoyukon on Sep 28, 2009. #

Anyone know of good method and/or spot that can be used to save the text if/when the UITextView’s keyboard is dismissed?

by cole on Oct 6, 2009. #

To answer my own question…this worked:

// Save the users comment
– (void)textViewDidEndEditing:(UITextView *)textView{

NSLog(@”textView.text: %@”, textView.text);

}

Just be sure you have implemented the UITextViewDelegate protocol in your .h file.

by cole on Oct 6, 2009. #

Thank you so much for this tip! Very useful!

by anon on Oct 17, 2009. #

Right on thanks soo much! Worked like a charm.

by zane on Dec 31, 2009. #

Thanks very much for this trick. I’ve been searching and searching for how to get the keyboard to dismiss on the “Done” button. This seems like a bit of a hack, but at the same time, it allows for the most flexibility of behavior so I can see why it doesn’t automatically dismiss.

Thanks again!

by Mishkin Berteig on Jan 3, 2010. #

This is how i did it and it works just fine,

– First register for keyboradDidShow notification(in viewDidLoad):
– have a button show up right above the end of the keyboard when the keyboard is shown(implemented in the notification)
– add target to that button so that it discards the keyboard by sending the resignFirstResponder message to the text view.
– also remove the button from the super view in the target method and it looks like the button is showing up with the keyboard. cheers.

– (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil];

….
}

-(void) keyboardDidShow: (NSNotification *)notif
{
NSLog(@”keyboard did show”);
hideKeyboardButton = [UIButton buttonWithType: UIButtonTypeCustom];
hideKeyboardButton.frame = CGRectMake(250, 173, 70, 30);
[hideKeyboardButton setTitle:@”Cancel” forState: UIControlStateNormal];
[hideKeyboardButton setBackgroundImage:[UIImage imageNamed:@”button.png”] forState: UIControlStateNormal];
[hideKeyboardButton addTarget: self action:@selector(hideKeyboard) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: hideKeyboardButton];
}

-(void) hideKeyboard
{
[hideKeyboardButton removeFromSuperview];
[yourTextView resignFirstResponder];
}

by Mk on Feb 1, 2010. #

This worked for me as the UITextView was being used so someone could add notes, (attribute for an entity in core data). I could not assume they would let the text wrap but they might wish to use a newline. Therefore the return key had to function as default. cheers

by T1bs on Mar 17, 2011. #

thanks for great tip.helped me a lot

by Sijo on Mar 25, 2010. #

Great work Man. U deserve kudos . Hoping 2 see some more code from your side. Thanks a lot !!!!

by Saurabh on Apr 1, 2010. #

This works very well for me and requires view little coding

– (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@”User touched”);
UITouch *touch = [touches anyObject];

if ([textView isFirstResponder] && [touch view] != textView) {
NSLog(@”The textView is currently being edited, and the user touched outside the text view”);
[textView resignFirstResponder];
}
}

by Hai Tran on Aug 6, 2010. #

How do you make it so when you tap done it will also retract the keyboard

by evan stoddard on Aug 17, 2011. #

thank you thank you thank you thank you thank you thank you thank you thank you

by checoschnaider on Jan 6, 2012. #

This is a very nice article for iphone application developers and It saved my time of development.

Thanks to write a nice article and post it on your blog publicly.

by Mahendera on Sep 11, 2010. #

Great!! Thanks a lot, solved my problem in 5 minutes….

by Riki on Feb 2, 2011. #

Really appreciate this and Thanks also go to those commenting, some very useful stuff there!

by T1bs on Mar 17, 2011. #

Thanks. Best wishes to you.

by Robert D on Apr 10, 2011. #

Thanks a lot,

here i found everything that i expected. Solve my probleme in only 10 minutes.

Keep writing article like that, very helpfull.

BB

by Teebo on Jul 29, 2011. #

I was actually stuck with this problem today…..got the solution….thanks alot

by Ruchi Kaintura on Dec 2, 2011. #

This works like a charm thank you.

by Rachel on Dec 16, 2011. #

Nice Example ,, Its working for me nice… :)

by M.A.Khan on May 17, 2012. #