Add placeholder text inside UITextView in Swift? Add placeholder text inside UITextView in Swift? ios ios

Add placeholder text inside UITextView in Swift?


Updated for Swift 4

UITextView doesn't inherently have a placeholder property so you'd have to create and manipulate one programmatically using UITextViewDelegate methods. I recommend using either solution #1 or #2 below depending on the desired behavior.

Note: For either solution, add UITextViewDelegate to the class and set textView.delegate = self to use the text view’s delegate methods.


Solution #1 - If you want the placeholder to disappear as soon as the user selects the text view:

First set the UITextView to contain the placeholder text and set it to a light gray color to mimic the look of a UITextField's placeholder text. Either do so in the viewDidLoad or upon the text view's creation.

textView.text = "Placeholder"textView.textColor = UIColor.lightGray

Then when the user begins to edit the text view, if the text view contains a placeholder (i.e. if its text color is light gray) clear the placeholder text and set the text color to black in order to accommodate the user's entry.

func textViewDidBeginEditing(_ textView: UITextView) {    if textView.textColor == UIColor.lightGray {        textView.text = nil        textView.textColor = UIColor.black    }}

Then when the user finishes editing the text view and it's resigned as the first responder, if the text view is empty, reset its placeholder by re-adding the placeholder text and setting its color to light gray.

func textViewDidEndEditing(_ textView: UITextView) {    if textView.text.isEmpty {        textView.text = "Placeholder"        textView.textColor = UIColor.lightGray    }}

Solution #2 - If you want the placeholder to show whenever the text view is empty, even if the text view’s selected:

First set the placeholder in the viewDidLoad:

textView.text = "Placeholder"textView.textColor = UIColor.lightGraytextView.becomeFirstResponder()textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

(Note: Since the OP wanted to have the text view selected as soon as the view loads, I incorporated text view selection into the above code. If this is not your desired behavior and you do not want the text view selected upon view load, remove the last two lines from the above code chunk.)

Then utilize the shouldChangeTextInRange UITextViewDelegate method, like so:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {    // Combine the textView text and the replacement text to    // create the updated text string    let currentText:String = textView.text    let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)    // If updated text view will be empty, add the placeholder    // and set the cursor to the beginning of the text view    if updatedText.isEmpty {        textView.text = "Placeholder"        textView.textColor = UIColor.lightGray        textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)    }    // Else if the text view's placeholder is showing and the    // length of the replacement string is greater than 0, set     // the text color to black then set its text to the    // replacement string     else if textView.textColor == UIColor.lightGray && !text.isEmpty {        textView.textColor = UIColor.black        textView.text = text    }    // For every other case, the text should change with the usual    // behavior...    else {        return true    }    // ...otherwise return false since the updates have already    // been made    return false}

And also implement textViewDidChangeSelection to prevent the user from changing the position of the cursor while the placeholder's visible. (Note: textViewDidChangeSelection is called before the view loads so only check the text view's color if the window is visible):

func textViewDidChangeSelection(_ textView: UITextView) {    if self.view.window != nil {        if textView.textColor == UIColor.lightGray {            textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)        }    }}



Floating Placeholder


It's simple, safe and reliable to position a placeholder label above a text view, set its font, color and manage placeholder visibility by tracking changes to the text view's character count.

Swift 3:

class NotesViewController : UIViewController, UITextViewDelegate {    @IBOutlet var textView : UITextView!    var placeholderLabel : UILabel!    override func viewDidLoad() {        super.viewDidLoad()        textView.delegate = self        placeholderLabel = UILabel()        placeholderLabel.text = "Enter some text..."        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (textView.font?.pointSize)!)        placeholderLabel.sizeToFit()        textView.addSubview(placeholderLabel)        placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)        placeholderLabel.textColor = UIColor.lightGray        placeholderLabel.isHidden = !textView.text.isEmpty    }    func textViewDidChange(_ textView: UITextView) {        placeholderLabel.isHidden = !textView.text.isEmpty    }}

Swift 2: Same, except:italicSystemFontOfSize(textView.font.pointSize), UIColor.lightGrayColor



Swift:

Add your text view programmatically or via Interface Builder, if the last, create the outlet:

@IBOutlet weak var yourTextView: UITextView!

Please add the delegate (UITextViewDelegate):

class ViewController: UIViewController, UITextViewDelegate {

In the viewDidLoad method, do add the following:

override func viewDidLoad() {        super.viewDidLoad()        // Do any additional setup after loading the view, typically from a nib.    yourTextView.delegate = self    yourTextView.text = "Placeholder text goes right here..."    yourTextView.textColor = UIColor.lightGray

Now let me introduce the magic part, add this function:

func textViewDidBeginEditing(_ textView: UITextView) {    if yourTextView.textColor == UIColor.lightGray {        yourTextView.text = ""        yourTextView.textColor = UIColor.black    }}

Do note that this will execute whenever editing starts, there we will check conditions to tell the state, using the color property.Setting text to nil i do not recommend. Right after that, we set the text color to desired, in this case, black.

Now add this function too:

func textViewDidEndEditing(_ textView: UITextView) {    if yourTextView.text == "" {        yourTextView.text = "Placeholder text ..."        yourTextView.textColor = UIColor.lightGray    }}

Let me insist, do not compare to nil, i have already tried that and it would not work. We then set the values back to placeholder style, and set the color back to placeholder color because it is a condition to check in textViewDidBeginEditing.