3

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?

Joseph Astrahan
  • 8,659
  • 12
  • 83
  • 154

3 Answers3

7

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.

Community
  • 1
  • 1
Timur Bernikovich
  • 5,660
  • 4
  • 45
  • 58
  • Let me attempt to add this 'Done' button I think this is a nice intuitive answer if I can get this to work. Give me 20 minutes... – Joseph Astrahan Dec 14 '16 at 09:11
  • Worked great, I modified the solution a bit for me by making it an extension to UITextView like this, extension UITextView – Joseph Astrahan Dec 14 '16 at 09:18
  • 1
    Hope you don't mind if I edited answer with my solution based on what you said , feel free to edit it back though. – Joseph Astrahan Dec 14 '16 at 09:19
  • Thanks for this answer. I agree that this is the best option for dismissing the keyboard. Much much better than the `shouldChangeTextInRange` solution or gesture recognizer. – greencardigan Mar 17 '18 at 08:40
1

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()
        }
    }
}
Mingebag
  • 748
  • 2
  • 20
  • 35
  • I'm interested in your solution also, what would you say the difference is in your solution versus the toolbar solution? Like benefits/drawbacks etc... – Joseph Astrahan Dec 14 '16 at 09:20
  • @JosephAstrahan Well the main difference is that I answered your question to give / keep the functionality of the "return key". Benefits as already mentioned no toolbar needed since we are not on pc ;). Drawbacks: User interaction is a bit off, since is not something the user is a familiar – Mingebag Dec 14 '16 at 09:27
  • Ok good to know I'll have to play with both ways of doing this and see what my client likes in this case. – Joseph Astrahan Dec 14 '16 at 09:38
0

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)
    }
}
TheNeil
  • 3,321
  • 2
  • 27
  • 52