Swift doesn’t support placeholders in UITextView’s natively, so here is the proper way to do it yourself in under 1 minute. You can checkout the preview GIF on Twitter !
//
// UITextViewPlaceholder.swift
// TextViewPlaceholder
//
// Copyright (c) 2017 Tijme Gommers <tijme@finnwea.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
/// Extend UITextView and implemented UITextViewDelegate to listen for changes
extension UITextView : UITextViewDelegate {
/// Resize the placeholder when the UITextView bounds change
override open var bounds : CGRect {
didSet {
self . resizePlaceholder ()
}
}
/// The UITextView placeholder text
public var placeholder : String ? {
get {
var placeholderText : String ?
if let placeholderLabel = self . viewWithTag ( 100 ) as? UILabel {
placeholderText = placeholderLabel . text
}
return placeholderText
}
set {
if let placeholderLabel = self . viewWithTag ( 100 ) as! UILabel ? {
placeholderLabel . text = newValue
placeholderLabel . sizeToFit ()
} else {
self . addPlaceholder ( newValue ! )
}
}
}
/// When the UITextView did change, show or hide the label based on if the UITextView is empty or not
///
/// - Parameter textView: The UITextView that got updated
public func textViewDidChange ( _ textView : UITextView ) {
if let placeholderLabel = self . viewWithTag ( 100 ) as? UILabel {
placeholderLabel . isHidden = ! self . text . isEmpty
}
}
/// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text
private func resizePlaceholder () {
if let placeholderLabel = self . viewWithTag ( 100 ) as! UILabel ? {
let labelX = self . textContainer . lineFragmentPadding
let labelY = self . textContainerInset . top - 2
let labelWidth = self . frame . width - ( labelX * 2 )
let labelHeight = placeholderLabel . frame . height
placeholderLabel . frame = CGRect ( x : labelX , y : labelY , width : labelWidth , height : labelHeight )
}
}
/// Adds a placeholder UILabel to this UITextView
private func addPlaceholder ( _ placeholderText : String ) {
let placeholderLabel = UILabel ()
placeholderLabel . text = placeholderText
placeholderLabel . sizeToFit ()
placeholderLabel . font = self . font
placeholderLabel . textColor = UIColor . lightGray
placeholderLabel . tag = 100
placeholderLabel . isHidden = ! self . text . isEmpty
self . addSubview ( placeholderLabel )
self . resizePlaceholder ()
self . delegate = self
}
}