How to dismiss keyboard for UITextView with return key?

317,509

Solution 1

UITextView does not have any methods which will be called when the user hits the return key. If you want the user to be able to add only one line of text, use a UITextField. Hitting the return and hiding the keyboard for a UITextView does not follow the interface guidelines.

Even then if you want to do this, implement the textView:shouldChangeTextInRange:replacementText: method of UITextViewDelegate and in that check if the replacement text is \n, hide the keyboard.

There might be other ways but I am not aware of any.

Solution 2

Figured I would post the snippet right here instead:

Make sure you declare support for the UITextViewDelegate protocol.

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

    if([text isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }

    return YES;
}

Swift 4.0 update:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if text == "\n" {
        textView.resignFirstResponder()
        return false
    }
    return true
}

Solution 3

I know this has been answered already but I don't really like using the string literal for the newline so here is what I did.

- (BOOL)textView:(UITextView *)txtView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if( [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location == NSNotFound ) {
        return YES;
    }

    [txtView resignFirstResponder];
    return NO;
}

Swift 4.0 update:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if (text as NSString).rangeOfCharacter(from: CharacterSet.newlines).location == NSNotFound {
    return true
}
txtView.resignFirstResponder()
return false
}

Solution 4

I know this has been answered a lot of times, but here are my two cents to the issue.

I found the answers by samvermette and ribeto really useful, and also the comment by maxpower in the ribeto's answer. But there is a problem with those approaches. The problem that matt mentions in the samvermette's answer and it's that if the user wants to paste something with a line break inside it, the keyboard would hide without pasting anything.

So my approach is a mixture of the three above mentioned solutions and only checking if the string entered is a new line when the length of the string is 1 so we make sure the user is typing instead of pasting.

Here is what I have done:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSRange resultRange = [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet] options:NSBackwardsSearch];
    if ([text length] == 1 && resultRange.location != NSNotFound) {
        [textView resignFirstResponder];
        return NO;
    }

    return YES;
}

Solution 5

A more elegant way is to dismiss the keyboard when the user taps somewhere outside of the keyboard's frame.

First, set your ViewController's view to the class "UIControl" in the identity inspector in UIBuilder. Control-drag the view into the ViewController's header file and link it as an action with the event as Touch Up Inside, such as:

ViewController.h

-(IBAction)dismissKeyboardOnTap:(id)sender;

In the main ViewController file, ViewController.m:

-(IBAction)dismissKeyboardOnTap:(id)sender
    {
         [[self view] endEditing:YES];
    }

You can require a double tap or long touch using similar techniques. You may need to set your ViewController to be a UITextViewDelegate and connect the TextView to the ViewController. This method works for both UITextView and UITextField.

Source: Big Nerd Ranch

EDIT: I'd also like to add that if you are using a UIScrollView, the above technique may not work as easily through the Interface Builder. In that case, you could use a UIGestureRecognizer and call the [[self view] endEditing:YES] method within it instead. An example would be:

-(void)ViewDidLoad{
    ....
    UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
        initWithTarget:self action:@selector(tap:)];
    [self.view addGestureRecognizer: tapRec];
    ....
}

-(void)tap:(UITapGestureRecognizer *)tapRec{
    [[self view] endEditing: YES];
}

When the user taps outside of the keyboard and does not tap an entry space, the keyboard will dismiss.

Share:
317,509
Chilly Zhong
Author by

Chilly Zhong

I'm a mobile app developer. I was developing for Windows Mobile and Blackberry. I begin to dig into iPhone Development since Feb, 2009. Working has become a brand-new page for me and for my life. I was working on a symbian app for a short time in March, 2010. And I begin to learn Android in Nov, 2010 and learn WindowsPhone in Nov, 2011. Now I'm working on an iOS framework similar to iAd and I'm happy to offer all kinds of libs to help other developers. Always walking down your own way and keep your faith.

Updated on May 01, 2020

Comments

  • Chilly Zhong
    Chilly Zhong about 4 years

    In IB's library, the introduction tells us that when the return key is pressed, the keyboard for UITextView will disappear. But actually the return key can only act as '\n'.

    I can add a button and use [txtView resignFirstResponder] to hide the keyboard.

    But is there a way to add the action for the return key in keyboard so that I needn't add UIButton?