I have done some research and found this post: Add placeholder text inside UITextView in Swift?
Incorporating the above example in my code, I have the following in a blank xcode UIKit project:
import UIKit
class ViewController: UIViewController {
var sampleTextView = UITextView()
let placeholderText = "Type Something"
let placeholderTextColor = UIColor.lightGray
let normalTextColor = UIColor.label
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray
sampleTextView.delegate = self
sampleTextView.text = placeholderText
sampleTextView.textColor = placeholderTextColor
sampleTextView.becomeFirstResponder()
sampleTextView.selectedTextRange = sampleTextView.textRange(from: sampleTextView.beginningOfDocument, to: sampleTextView.beginningOfDocument)
view.addSubview(sampleTextView)
sampleTextView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
sampleTextView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
sampleTextView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10),
sampleTextView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
sampleTextView.heightAnchor.constraint(equalToConstant: 100)
])
}
}
extension ViewController: UITextViewDelegate {
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = placeholderText
textView.textColor = placeholderTextColor
}
}
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 = placeholderText
textView.textColor = placeholderTextColor
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 == placeholderTextColor && !text.isEmpty {
textView.textColor = normalTextColor
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
}
func textViewDidChangeSelection(_ textView: UITextView) {
if self.view.window != nil {
if textView.textColor == placeholderTextColor {
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
}
}
}
But I have two bugs with this that for the life of me, I can't work out:
- This first is using the predictive text above the keyboard toolbar. The first selected work is repeated - see screenshot below:
- If typing, the keyboard's SHIFT key is pressed as expected for the first letter, but then stays pressed for the second one as well - see screenshot below:
Apologies if these are basic but I'm stumped.