Wie kann ich einen Platzhalter in einem UITextView
hinzufügen, ähnlich wie bei UITextField
, in Swift
?
Antworten
Zu viele Anzeigen?Protokollversion von clearlight's Antwort oben, weil Protokolle großartig sind. Füge es überall ein, wo du möchtest. Dunk!
extension UITextViewPlaceholder where Self: UIViewController {
// Verwende dies in der ViewDidLoad-Methode des ViewControllers.
func addPlaceholder(text: String, toTextView: UITextView, font: UIFont? = nil) {
placeholderLabel = UILabel()
placeholderLabel.text = text
placeholderLabel.font = font ?? UIFont.italicSystemFont(ofSize: (toTextView.font?.pointSize)!)
placeholderLabel.sizeToFit()
toTextView.addSubview(placeholderLabel)
placeholderLabel.frame.origin = CGPoint(x: 5, y: (toTextView.font?.pointSize)! / 2)
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.isHidden = !toTextView.text.isEmpty
}
// Verwende diese Funktion in der textViewDidChange-Delegatenmethode des ViewControllers.
func textViewWithPlaceholderDidChange(_ textView: UITextView) {
placeholderLabel.isHidden = !textView.text.isEmpty
}
}
Hier ist meine einfache Version von UITextView
mit Platzhalter. Die Hauptidee ist:
- Platzhalter ausblenden, wenn der Benutzer mit der Eingabe beginnt und der Platzhalter sichtbar ist
-
Platzhalter anzeigen, wenn der Benutzer mit der Eingabe fertig ist und der
Text
des Textfelds leer ist.class PlaceholderTextView: UITextView {
var placeholder = "" { didSet { if isPlaceholderVisible { showPlaceholder() } } } var isPlaceholderVisible = true { didSet { isPlaceholderVisible ? showPlaceholder() : hidePlaceholder() } } init() { super.init(frame: .zero, textContainer: nil) delegate = self } required init?(coder: NSCoder) { fatalError("init(coder:) wurde nicht implementiert") } private func showPlaceholder() { text = placeholder // Andere Einstellungen wie Textfarbe für Platzhalter setzen, ... } private func hidePlaceholder() { text = "" // Andere Einstellungen wie Textfarbe für normale Eingabe setzen, ... }
}
extension PlaceholderTextView: UITextViewDelegate { func textViewDidBeginEditing(_ textView: UITextView) { if isPlaceholderVisible { isPlaceholderVisible = false } }
func textViewDidEndEditing(_ textView: UITextView) { if text.isEmpty { isPlaceholderVisible = true } }
}
TEXT VIEW DELEGATE METHODEN
Verwenden Sie diese beiden Delegate-Methoden und schreiben Sie auch UITextViewDelegate in Ihre Klasse
func textViewDidBeginEditing(_ textView: UITextView) {
if (commentsTextView.text == "Geben Sie Ihre Kommentare ein")
{
commentsTextView.text = nil
commentsTextView.textColor = UIColor.darkGray
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if commentsTextView.text.isEmpty
{
commentsTextView.text = "Geben Sie Ihre Kommentare ein"
commentsTextView.textColor = UIColor.darkGray
}
textView.resignFirstResponder()
}
Hier ist etwas, das in ein UIStackView
eingefügt werden kann, es wird sich selbst dimensionieren, indem es eine interne Höhenbeschränkung verwendet. Möglicherweise sind Anpassungen erforderlich, um spezifische Anforderungen zu erfüllen.
import UIKit
public protocol PlaceholderTextViewDelegate: class {
func placeholderTextViewTextChanged(_ textView: PlaceholderTextView, text: String)
}
public class PlaceholderTextView: UIView {
public weak var delegate: PlaceholderTextViewDelegate?
private var heightConstraint: NSLayoutConstraint?
public override init(frame: CGRect) {
self.allowsNewLines = true
super.init(frame: frame)
self.heightConstraint = self.heightAnchor.constraint(equalToConstant: 0)
self.heightConstraint?.isActive = true
self.addSubview(self.placeholderTextView)
self.addSubview(self.textView)
self.pinToCorners(self.placeholderTextView)
self.pinToCorners(self.textView)
self.updateHeight()
}
public override func didMoveToSuperview() {
super.didMoveToSuperview()
self.updateHeight()
}
private func pinToCorners(_ view: UIView) {
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(equalTo: self.leadingAnchor),
view.trailingAnchor.constraint(equalTo: self.trailingAnchor),
view.topAnchor.constraint(equalTo: self.topAnchor),
view.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
// Accessors
public var text: String? {
didSet {
self.textView.text = text
self.textViewDidChange(self.textView)
self.updateHeight()
}
}
public var textColor: UIColor? {
didSet {
self.textView.textColor = textColor
self.updateHeight()
}
}
public var font: UIFont? {
didSet {
self.textView.font = font
self.placeholderTextView.font = font
self.updateHeight()
}
}
public override var tintColor: UIColor? {
didSet {
self.textView.tintColor = tintColor
self.placeholderTextView.tintColor = tintColor
}
}
public var placeholderText: String? {
didSet {
self.placeholderTextView.text = placeholderText
self.updateHeight()
}
}
public var placeholderTextColor: UIColor? {
didSet {
self.placeholderTextView.textColor = placeholderTextColor
self.updateHeight()
}
}
public var allowsNewLines: Bool
public required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private lazy var textView: UITextView = self.newTextView()
private lazy var placeholderTextView: UITextView = self.newTextView()
private func newTextView() -> UITextView {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = false
textView.delegate = self
textView.backgroundColor = .clear
return textView
}
private func updateHeight() {
let maxSize = CGSize(width: self.frame.size.width, height: .greatestFiniteMagnitude)
let textViewSize = self.textView.sizeThatFits(maxSize)
let placeholderSize = self.placeholderTextView.sizeThatFits(maxSize)
let maxHeight = ceil(CGFloat.maximum(textViewSize.height, placeholderSize.height))
self.heightConstraint?.constant = maxHeight
}
}
extension PlaceholderTextView: UITextViewDelegate {
public func textViewDidChangeSelection(_: UITextView) {
self.placeholderTextView.alpha = self.textView.text.isEmpty ? 1 : 0
self.updateHeight()
}
public func textViewDidChange(_: UITextView) {
self.delegate?.placeholderTextViewTextChanged(self, text: self.textView.text)
}
public func textView(_: UITextView, shouldChangeTextIn _: NSRange,
replacementText text: String) -> Bool {
let containsNewLines = text.rangeOfCharacter(from: .newlines)?.isEmpty == .some(false)
guard !containsNewLines || self.allowsNewLines else { return false }
return true
}
}
Unsere Lösung vermeidet das Manipulieren der UITextView
text
und textColor
Eigenschaften, was praktisch ist, wenn Sie einen Zeichenzähler pflegen.
Es ist einfach:
1) Erstellen Sie eine Dummy-UITextView
in Storyboard mit denselben Eigenschaften wie die Master-UITextView
. Weisen Sie dem Dummy-Text Platzhaltertext zu.
2) Ausrichten der oberen, linken und rechten Kanten der beiden UITextViews.
3) Platzieren Sie den Dummy hinter dem Master.
4) Überschreiben Sie die textViewDidChange(textView:)
Delegatenfunktion des Masters und zeigen Sie den Dummy an, wenn der Master 0 Zeichen hat. Andernfalls zeigt den Master an.
Dies setzt voraus, dass beide UITextViews
transparente Hintergründe haben. Wenn dies nicht der Fall ist, platzieren Sie den Dummy oben, wenn es 0 Zeichen gibt, und schieben Sie ihn darunter, wenn es mehr als 0 Zeichen gibt. Sie müssen auch die Responder austauschen, um sicherzustellen, dass der Cursor dem richtigen UITextView
folgt.