Make Keyboard Go Away For UITextView While Keeping Return Functionality

1.4k views Asked by At

There is lots of answers for how to make the keyboard go away when you press the return key, but I want the functionality of the return key still so users can make new lines but I also need a way to still close the keyboard.

Some things I have considered are Gesture Recognizers to close the keyboard, but that might not be intuitive. Thoughts and best practices here are appreciated.

Please note before answering I already have a Gesture Recognizer if the user clicks outside the UITextView to close any keyboards but this particular UITextView takes up the entire screen and as such tapping in it doesn't work.

My current code I'm using to do that was taken from another post and looks like below.

extension UIViewController {
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
    }

    func dismissKeyboard() {
        view.endEditing(true)
    }
}

All I have to do is call this function in my viewcontroller where I want the tap to close the keyboards for me anywhere from any text controls. It's been working great so far, but clicking on the controls themselves still creates an issue in which the keyboard does not go away.

What is the best way to close the keyboard for a UITextView that takes up the full screen?

3

There are 3 answers

4
Tim Bernikovich On BEST ANSWER

I propose you to add toolbar with "Done" button above keyboard. There are a lot of tutorials how to do this, no reason to copy SO answers, just check: How to add a 'Done' button to numpad keyboard in iOS

Possible Solution Here

extension UITextView {

    func addDoneButton() {
        let keyboardToolbar = UIToolbar()
        keyboardToolbar.sizeToFit()
        let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                            target: nil, action: nil)
        let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done,
                                            target: self, action: #selector(UIView.endEditing(_:)))
        keyboardToolbar.items = [flexBarButton, doneBarButton]
        self.inputAccessoryView = keyboardToolbar
    }
}

To use it simply call addDoneButton on any UITextView from now on.

3
Mingebag On

Add this method in your view controller.

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

As well as this and that should do the trick ** Dismiss keyboard when tapped outside the keyboard or textView

*/
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    if let touch = touches.anyObject() as? UITouch {
        if touch.phase == UITouchPhase.Began {
            textField?.resignFirstResponder()
        }
    }
}
0
TheNeil On

So, based on some of the other answers here, I established the following subclass for UITextView, which has an interface-builder-compatible field to enable multi-line Return functionality, and Done functionality at the same time.

Hope it helps.

Swift v5

import UIKit
@IBDesignable class MultiLineTextView: UITextView {

    @IBInspectable var multiLineWithDoneButton: Bool = false

    override func didMoveToWindow() {
        super.didMoveToWindow()
        if multiLineWithDoneButton { // Add a toolbar with a done button to the keyboard, if required
            returnKeyType = UIReturnKeyType.default
            let toolbar:UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0,  width: Int(self.frame.size.width), height: 45))
            let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
            let doneButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneButtonPressed))
            toolbar.setItems([flexibleSpace, doneButton], animated: false)
            toolbar.sizeToFit()
            inputAccessoryView = toolbar
        } else {
            returnKeyType = UIReturnKeyType.done
        }
    }

    @objc private func doneButtonPressed() {
        endEditing(true)
    }
}