ios - pro - scanbot vip




Textansicht(UITextView) Platzhalter Swift (20)

Schwimmender Platzhalter

Es ist einfach, sicher und zuverlässig, ein Platzhalteretikett über einer Textansicht zu platzieren, seine Schriftart und Farbe festzulegen und die Sichtbarkeit von Platzhaltern zu verwalten, indem Änderungen an der Zeichenanzahl der Textansicht verfolgt werden.

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: Gleich, außer: italicSystemFontOfSize(textView.font.pointSize) , UIColor.lightGrayColor

Ich mache eine Anwendung, die eine UITextView . Jetzt möchte ich, dass die Textansicht einen Platzhalter hat, der dem Platzhalter ähnelt, den Sie für ein Textfeld festlegen können. Wie würden Sie dies mit swift erreichen?

Weiß jemand, wie man das macht?


Schnelle Antwort

Hier ist die benutzerdefinierte Klasse, die Platzhalter animiert.

extension UITextViewPlaceholder where Self: UIViewController {

    // Use this in ViewController's ViewDidLoad method.
    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
    }

    // Use this function in the ViewController's textViewDidChange delegate method.
    func textViewWithPlaceholderDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
}

Hier ist meine Art, dieses Problem zu lösen ( Swift 4 ):

Die Idee war, eine möglichst einfache Lösung zu schaffen, die die Verwendung von Platzhaltern in verschiedenen Farben ermöglicht, deren Größe auf die Größe von Platzhaltern angepasst wird und die nicht überschreibt, während delegate alle UITextView Funktionen wie erwartet funktionieren.

import UIKit

class PlaceholderTextView: UITextView {
    var placeholderColor: UIColor = .lightGray
    var defaultTextColor: UIColor = .black

    private var isShowingPlaceholder = false {
        didSet {
            if isShowingPlaceholder {
                text = placeholder
                textColor = placeholderColor
            } else {
                textColor = defaultTextColor
            }
        }
    }

    var placeholder: String? {
        didSet {
            isShowingPlaceholder = !hasText
        }
    }

    @objc private func textViewDidBeginEditing(notification: Notification) {
        textColor = defaultTextColor
        if isShowingPlaceholder { text = nil }
    }

    @objc private func textViewDidEndEditing(notification: Notification) {
        isShowingPlaceholder = !hasText
    }

    // MARK: - Construction -
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup() {
        NotificationCenter.default.addObserver(self, selector: #selector(textViewDidBeginEditing(notification:)), name: UITextView.textDidBeginEditingNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(textViewDidEndEditing(notification:)), name: UITextView.textDidEndEditingNotification, object: nil)
    }

    // MARK: - Destruction -
    deinit { NotificationCenter.default.removeObserver(self) }
}

Ich kann wegen des guten Rufs keinen Kommentar hinzufügen. Fügen Sie in @clearlight answer einen weiteren Delegiertenbedarf hinzu.

func textViewDidBeginEditing(_ textView: UITextView) { 
        cell.placeholderLabel.isHidden = !textView.text.isEmpty
}

ist nötig

da textViewDidChange wird nicht erstmal gerufen


Ich musste die Warteschlange auslösen, damit mein Platzhaltertext nach Abschluss der Bearbeitung wieder angezeigt wurde.

func textViewDidBeginEditing(_ textView: UITextView) {

    if textView.text == "Description" {
        textView.text = nil
    }
}

func textViewDidEndEditing(_ textView: UITextView) {

    if textView.text.isEmpty {
        DispatchQueue.main.async {
            textView.text = "Description"
        }
    }
}

In ios gibt es keine solche Eigenschaft, um Platzhalter direkt in TextView hinzuzufügen. Stattdessen können Sie eine Beschriftung hinzufügen und die Änderung in TextView anzeigen / ausblenden. SWIFT 2.0 und stellen Sie sicher, dass Sie das textviewdelegate implementieren

func textViewDidChange(TextView: UITextView)
{

 if  txtShortDescription.text == ""
    {
        self.lblShortDescription.hidden = false
    }
    else
    {
        self.lblShortDescription.hidden = true
    }

}

Nein, für die Textansicht ist kein Platzhalter verfügbar. Sie müssen eine Beschriftung darüber setzen, wenn der Benutzer in der Textansicht eingibt, und diese dann ausblenden oder den Standardwert festlegen, wenn der Benutzer eingibt, um alle Werte zu entfernen.


Protokollversion der Antwort von , da Protokolle großartig sind. Kommen Sie herein, wo immer Sie wollen. Dunk!

func textViewDidBeginEditing(_ textView: UITextView) {
    if (commentsTextView.text == "Type Your Comments")
    {
        commentsTextView.text = nil
        commentsTextView.textColor = UIColor.darkGray
    }
}

func textViewDidEndEditing(_ textView: UITextView) {
    if commentsTextView.text.isEmpty
    {
        commentsTextView.text = "Type Your Comments"
        commentsTextView.textColor = UIColor.darkGray
    }
    textView.resignFirstResponder()
}

Unsere Lösung vermeidet das Durcheinander mit den Eigenschaften UITextView text und textColor , was praktisch ist, wenn Sie einen Zeichenzähler verwalten.

Es ist einfach:

1) Erstellen Sie UITextView in Storyboard einen Dummy mit den gleichen Eigenschaften wie der Master UITextView . Ordnen Sie dem Dummy-Text Platzhaltertext zu.

2) Richten Sie die oberen, linken und rechten Kanten der beiden aus UITextViews.

3) Platzieren Sie den Dummy hinter dem Master.

4) Überschreiben Sie die textViewDidChange(textView:) Delegate-Funktion des Masters und zeigen Sie den Dummy an, wenn der Master 0 Zeichen hat. Andernfalls zeigen Sie den Master.

Dies setzt voraus, dass beide UITextViews transparente Hintergründe haben. Ist dies nicht der Fall, platzieren Sie den Dummy oben, wenn 0 Zeichen vorhanden sind, und schieben Sie ihn unten, wenn> 0 Zeichen vorhanden sind. Sie müssen auch die Antwortenden tauschen, um sicherzustellen, dass der Cursor rechts folgt UITextView .


Basierend auf einigen der großartigen Vorschläge hier konnte ich die folgende UITextView , Interface-Builder-kompatible Unterklasse von UITextView , die:

  • Enthält konfigurierbaren Platzhaltertext, der genau wie der von UITextField .
  • Benötigt keine zusätzlichen Unteransichten oder Einschränkungen.
  • Erfordert keine Delegierung oder anderes Verhalten vom ViewController.
  • Benötigt keine Benachrichtigungen.
  • Hält diesen Text vollständig von allen externen Klassen getrennt, die die Texteigenschaft des Felds betrachten.

Verbesserungsvorschläge sind willkommen, insbesondere, wenn es eine Möglichkeit gibt, die Platzhalterfarbe von iOS programmgesteuert abzurufen, anstatt sie hart zu codieren.

Swift v5:

    txtVw!.autocorrectionType = UITextAutocorrectionType.No
    txtVw!.text = "Write your Placeholder"
    txtVw!.textColor = UIColor.lightGrayColor()



func textViewDidBeginEditing(textView: UITextView) {
    if (txtVw?.text == "Write your Placeholder")

    {
        txtVw!.text = nil
        txtVw!.textColor = UIColor.blackColor()
    }
}

func textViewDidEndEditing(textView: UITextView) {
    if txtVw!.text.isEmpty
    {
        txtVw!.text = "Write your Placeholder"
        txtVw!.textColor = UIColor.lightGrayColor()
    }
    textView.resignFirstResponder()
}

Eine weitere Lösung (Swift 3):

import UIKit
@IBDesignable class TextViewWithPlaceholder: UITextView {

    override var text: String! { // Ensures that the placeholder text is never returned as the field's text
        get {
            if showingPlaceholder {
                return "" // When showing the placeholder, there's no real text to return
            } else { return super.text }
        }
        set { super.text = newValue }
    }
    @IBInspectable var placeholderText: String = ""
    @IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) // Standard iOS placeholder color (#C7C7CD). See https://.com/questions/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
    private var showingPlaceholder: Bool = true // Keeps track of whether the field is currently showing a placeholder

    override func didMoveToWindow() {
        super.didMoveToWindow()
        if text.isEmpty {
            showPlaceholderText() // Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
        }
    }

    override func becomeFirstResponder() -> Bool {
        // If the current text is the placeholder, remove it
        if showingPlaceholder {
            text = nil
            textColor = nil // Put the text back to the default, unmodified color
            showingPlaceholder = false
        }
        return super.becomeFirstResponder()
    }

    override func resignFirstResponder() -> Bool {
        // If there's no text, put the placeholder back
        if text.isEmpty {
            showPlaceholderText()
        }
        return super.resignFirstResponder()
    }

    private func showPlaceholderText() {
        showingPlaceholder = true
        textColor = placeholderTextColor
        text = placeholderText
    }
}

Ergebnis



Ich bin überrascht, dass niemand NSTextStorageDelegate erwähnt NSTextStorageDelegate . Die Methoden von UITextViewDelegate werden nur durch Benutzerinteraktion ausgelöst, nicht jedoch programmgesteuert. Wenn Sie beispielsweise die Texteigenschaft einer Textansicht programmgesteuert festlegen, müssen Sie die Sichtbarkeit des Platzhalters selbst festlegen, da die Delegatmethoden nicht aufgerufen werden.

Mit der textStorage(_:didProcessEditing:range:changeInLength:) -Methode von textStorage(_:didProcessEditing:range:changeInLength:) werden Sie jedoch über jede Änderung des Texts benachrichtigt, auch wenn dies programmgesteuert erfolgt. Weisen Sie es einfach so zu:

textView.textStorage.delegate = self

(In UITextView ist diese Delegate-Eigenschaft standardmäßig gleich nil , sodass sie sich nicht auf das Standardverhalten auswirkt.)

Kombiniert man es mit der UILabel Technik, die @clearlight demonstriert, kann man die gesamte placeholder UITextView problemlos in eine Erweiterung UITextView .

extension UITextView {

    private class PlaceholderLabel: UILabel { }

    private var placeholderLabel: PlaceholderLabel {
        if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
            return label
        } else {
            let label = PlaceholderLabel(frame: .zero)
            label.font = font
            addSubview(label)
            return label
        }
    }

    @IBInspectable
    var placeholder: String {
        get {
            return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
        }
        set {
            let placeholderLabel = self.placeholderLabel
            placeholderLabel.text = newValue
            placeholderLabel.numberOfLines = 0
            let width = frame.width - textContainer.lineFragmentPadding * 2
            let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
            placeholderLabel.frame.size.height = size.height
            placeholderLabel.frame.size.width = width
            placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)

            textStorage.delegate = self
        }
    }

}

extension UITextView: NSTextStorageDelegate {

    public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) {
        if editedMask.contains(.editedCharacters) {
            placeholderLabel.isHidden = !text.isEmpty
        }
    }

}

Beachten Sie, dass die Verwendung einer privaten (verschachtelten) Klasse namens PlaceholderLabel . Es ist überhaupt nicht implementiert, bietet uns jedoch eine Möglichkeit, die Platzhalterbezeichnung zu identifizieren. Dies ist weitaus schneller als die Verwendung der tag -Eigenschaft.

Mit diesem Ansatz können Sie den Delegaten von UITextView einer anderen Person zuweisen.

Sie müssen nicht einmal die Klassen Ihrer Textansichten ändern. UITextView Sie einfach die Erweiterung (en) hinzu, und Sie können jedem UITextView in Ihrem Projekt, auch im Interface Builder, eine Platzhalterzeichenfolge zuweisen.

Ich habe die Implementierung einer placeholderColor -Eigenschaft aus Gründen der Übersichtlichkeit weggelassen, sie kann jedoch mit einer ähnlichen berechneten Variablen wie die placeholder -Eigenschaft auch für ein paar weitere Zeilen implementiert werden.


Ich habe dazu zwei verschiedene Textansichten verwendet:

  1. Eine im Hintergrund, die als Platzhalter verwendet wird.
  2. Eine im Vordergrund (mit transparentem Hintergrund), die der Benutzer tatsächlich eingibt.

Die Idee ist, dass der Platzhalter im Hintergrund verschwindet, sobald der Benutzer mit der Eingabe von Inhalten in der Vordergrundansicht beginnt (und erneut angezeigt wird, wenn der Benutzer alles löscht). Es verhält sich also genau wie ein Platzhalter für das einzeilige Textfeld.

Hier ist der Code, den ich dafür verwendet habe. Beachten Sie, dass descriptionField das Feld ist, das der Benutzer eingibt, und descriptionPlaceholder das Feld im Hintergrund.

yourTextView.placeholder = "Placeholder" 

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.characters.count > 0
        }
    }

    /// 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.characters.count > 0

        self.addSubview(placeholderLabel)
        self.resizePlaceholder()
        self.delegate = self
    }
}

Ich weiß nicht, warum die Leute dieses Problem so komplizieren ... Es ist ziemlich einfach und unkompliziert. Hier ist eine Unterklasse von UITextView, die die angeforderte Funktionalität bietet.

func textViewShouldBeginEditing(textView: UITextView) -> Bool {        
    // Set cursor to the beginning if placeholder is set
    if textView.textColor == UIColor.lightGrayColor() {
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }

    return true
}

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    // Remove placeholder
    if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 {
        textView.text = ""
        textView.textColor = UIColor.blackColor()
    }

    if text == "\n" {
        textView.resignFirstResponder()
        return false
    }

    return true
}

func textViewDidChange(textView: UITextView) {
    // Set placeholder if text is empty
    if textView.text.isEmpty {
        textView.text = NSLocalizedString("Hint", comment: "hint")
        textView.textColor = UIColor.lightGrayColor()
        textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
    }
}

func textViewDidChangeSelection(textView: UITextView) {
    // Set cursor to the beginning if placeholder is set
    let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)

    // Do not change position recursively
    if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition {
        textView.selectedTextRange = firstPosition
    }
}

Im Gegensatz zu fast jeder Antwort auf diesen Beitrag verfügt UITextView über eine Platzhaltereigenschaft. Aus Gründen, die ich nicht verstehe, wird es nur in IB als solches angezeigt:

<userDefinedRuntimeAttributes>
  <userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>

Wenn Sie Storyboards verwenden und ein statischer Platzhalter ausreicht, legen Sie die Eigenschaft im Inspektor fest.

Sie können diese Eigenschaft auch in folgendem Code festlegen:

textView.setValue("My Placeholder", forKeyPath: "placeholder")

Es ist bewölkt und wetterbedingt. Der Zugriff darauf erfolgt über eine private API, da die Unterkunft exponiert ist.

Ich habe nicht versucht, mit dieser Methode zu übermitteln. Aber ich werde diesen Weg in Kürze einreichen und diese Antwort entsprechend aktualisieren.

AKTUALISIEREN:

Ich habe diesen Code in mehreren Versionen ohne Probleme von Apple ausgeliefert.

UPDATE: Dies funktioniert nur in Xcode vor 11.2


Swift 3.2

extension EditProfileVC:UITextViewDelegate{

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

Zuerst, wenn der Benutzer mit der Bearbeitung des Aufrufs textViewDidBeginEditing beginnt und dann überprüft, ob die Farbe des Textes grau bedeutet, dass der Benutzer nichts geschrieben hat, dann als Textansicht null festgelegt und die Farbe für die Benutzer-SMS in schwarz geändert.

Wenn die Bearbeitung von textViewDidEndEditing durch den Benutzer beendet wird, rufen Sie textViewDidEditing auf und überprüfen Sie, ob der Benutzer in der Textansicht nichts geschrieben hat. Der Text wird in grauer Farbe mit dem Text "PlaceHolder" festgelegt.


func setPlaceholder(){
var placeholderLabel = UILabel()
        placeholderLabel.text = "Describe your need..."
        placeholderLabel.font = UIFont.init(name: "Lato-Regular", size: 15.0) ?? UIFont.boldSystemFont(ofSize: 14.0)
        placeholderLabel.sizeToFit()
        descriptionTextView.addSubview(placeholderLabel)
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (descriptionTextView.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !descriptionTextView.text.isEmpty
}



//Delegate Method.

func textViewDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
	


Aktualisiert für Swift 4

UITextView besitzt von Natur aus keine Platzhaltereigenschaft, sodass Sie eine mit UITextViewDelegate Methoden programmgesteuert erstellen und UITextViewDelegate . Ich empfehle, je nach gewünschtem Verhalten entweder die Lösung 1 oder 2 zu verwenden.

Hinweis: UITextViewDelegate Sie für beide Lösungen UITextViewDelegate zur Klasse hinzu und setzen Sie textView.delegate = self , um die UITextViewDelegate der textView.delegate = self zu verwenden.

Lösung 1 - Wenn der Platzhalter ausgeblendet werden soll, sobald der Benutzer die Textansicht auswählt:

UITextView , dass es den Platzhaltertext enthält, und setzen Sie es auf eine hellgraue Farbe, um das Erscheinungsbild des Platzhaltertextes eines UITextField zu imitieren. Tun Sie dies entweder in viewDidLoad oder bei der Erstellung der viewDidLoad .

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

Wenn der Benutzer dann mit dem Bearbeiten der Textansicht beginnt und die Textansicht einen Platzhalter enthält (dh wenn ihre Textfarbe hellgrau ist), löschen Sie den Platzhaltertext und setzen Sie die Textfarbe auf Schwarz, um die Eingabe des Benutzers zu ermöglichen.

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

Wenn der Benutzer die Bearbeitung der Textansicht beendet und diese als Ersthelfer zurückgetreten ist, setzen Sie den Platzhalter zurück, indem Sie den Platzhaltertext erneut hinzufügen und die Farbe auf Hellgrau einstellen, wenn die Textansicht leer ist.

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

Lösung 2 - Wenn der Platzhalter angezeigt werden soll, wenn die Textansicht leer ist, auch wenn die Textansicht ausgewählt ist:

Setzen Sie zuerst den Platzhalter in viewDidLoad :

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

textView.becomeFirstResponder()

textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)

(Hinweis: Da das OP wollte, dass die Textansicht ausgewählt wird, sobald die Ansicht geladen wird, habe ich die Auswahl der Textansicht in den obigen Code aufgenommen. Wenn dies nicht Ihr gewünschtes Verhalten ist und Sie nicht möchten, dass die Textansicht beim Laden der Ansicht ausgewählt wird, Entfernen Sie die letzten beiden Zeilen aus dem obigen Codeabschnitt.)

shouldChangeTextInRange UITextViewDelegate dann die UITextViewDelegate Methode UITextViewDelegate wie UITextViewDelegate :

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
}

Implementieren textViewDidChangeSelection außerdem textViewDidChangeSelection , um zu verhindern, dass der Benutzer die Position des Cursors ändert, während der Platzhalter sichtbar ist. (Hinweis: textViewDidChangeSelection wird vor dem textViewDidChangeSelection der Ansicht aufgerufen. Überprüfen Sie daher die Farbe der textViewDidChangeSelection nur, wenn das Fenster sichtbar ist.)

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

SET-Wert beim Laden der Ansicht

import UIKit

protocol PlaceholderTextViewDelegate {
    func placeholderTextViewDidChangeText(_ text:String)
    func placeholderTextViewDidEndEditing(_ text:String)
}

final class PlaceholderTextView: UITextView {

    var notifier:PlaceholderTextViewDelegate?

    var placeholder: String? {
        didSet {
            placeholderLabel?.text = placeholder
        }
    }
    var placeholderColor = UIColor.lightGray
    var placeholderFont = UIFont.appMainFontForSize(14.0) {
        didSet {
            placeholderLabel?.font = placeholderFont
        }
    }

    fileprivate var placeholderLabel: UILabel?

    // MARK: - LifeCycle

    init() {
        super.init(frame: CGRect.zero, textContainer: nil)
        awakeFromNib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        self.delegate = self
        NotificationCenter.default.addObserver(self, selector: #selector(PlaceholderTextView.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: nil)

        placeholderLabel = UILabel()
        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.text = placeholder
        placeholderLabel?.textAlignment = .left
        placeholderLabel?.numberOfLines = 0
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        placeholderLabel?.font = placeholderFont

        var height:CGFloat = placeholderFont.lineHeight
        if let data = placeholderLabel?.text {

            let expectedDefaultWidth:CGFloat = bounds.size.width
            let fontSize:CGFloat = placeholderFont.pointSize

            let textView = UITextView()
            textView.text = data
            textView.font = UIFont.appMainFontForSize(fontSize)
            let sizeForTextView = textView.sizeThatFits(CGSize(width: expectedDefaultWidth,
                                                               height: CGFloat.greatestFiniteMagnitude))
            let expectedTextViewHeight = sizeForTextView.height

            if expectedTextViewHeight > height {
                height = expectedTextViewHeight
            }
        }

        placeholderLabel?.frame = CGRect(x: 5, y: 0, width: bounds.size.width - 16, height: height)

        if text.isEmpty {
            addSubview(placeholderLabel!)
            bringSubview(toFront: placeholderLabel!)
        } else {
            placeholderLabel?.removeFromSuperview()
        }
    }

    func textDidChangeHandler(notification: Notification) {
        layoutSubviews()
    }

}

extension PlaceholderTextView : UITextViewDelegate {
    // MARK: - UITextViewDelegate
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if(text == "\n") {
            textView.resignFirstResponder()
            return false
        }
        return true
    }

    func textViewDidChange(_ textView: UITextView) {
        notifier?.placeholderTextViewDidChangeText(textView.text)
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        notifier?.placeholderTextViewDidEndEditing(textView.text)
    }
}




placeholder