Swift'te bir UITextView içine yer tutucu metni nasıl ekleyebilirim?


316

A kullanan bir uygulama yapıyorum UITextView. Şimdi Metin Görünümünde, Metin Alanı için ayarlayabileceğinize benzer bir yer tutucu olmasını istiyorum. Swift kullanarak bunu nasıl başardınız?


Bu, UITextView ile iOS geliştirmede eski bir sorundur. Burada belirtilenler gibi alt sınıflar yazdım: stackoverflow.com/a/1704469/1403046 . Avantajı, yine de bir temsilci olabilir ve aynı zamanda mantığı yeniden uygulamak zorunda kalmadan sınıfı birden çok yerde kullanabilirsiniz.
cjwirth

Proje için swift kullanırken alt sınıfınızı nasıl kullanırım? Köprü dosyası mı kullanıyorsunuz?
StevenR

Bunu yapabilir veya Swift'te yeniden uygulayabilirsiniz. Yanıttaki kod olması gerekenden daha uzun. Ana nokta, metin değiştiğinde bildirim aldığınız yönteme eklediğiniz etiketi göstermek / gizlemektir.
cjwirth

GitHub'dan UIFloatLabelTextView örneğini kullanabilirsiniz. Bu, yer tutucuyu yazarken en üstte tutuyor. Gerçekten ilginç bir tane! github.com/ArtSabintsev/UIFloatLabelTextView
Jayprakash Dubey

2
Dürüst olmak gerekirse, bunu başarmanın en kolay yolu, özel bir textView'a sahip olmak ve sadece metin olmadığında textView üzerine çizilen yer tutucu metni eklemektir. durum yönetimi (metnin ne zaman olması gerektiği / olmaması gerektiğinde yanlış pozitifler dahil)
TheCodingArt

Yanıtlar:


649

Swift 4 için güncellendi

UITextViewdoğası gereği bir yer tutucu özelliğine sahip olmadığından, UITextViewDelegateyöntemleri kullanarak programlı olarak bir tane oluşturmanız ve değiştirmeniz gerekir . İstenen davranışa bağlı olarak aşağıdaki # 1 veya # 2 çözümünü kullanmanızı öneririm.

Not: Her iki çözüm UITextViewDelegateiçin de sınıfa ekleyin textView.delegate = selfve metin görünümünün temsilci yöntemlerini kullanacak şekilde ayarlayın .


Çözüm # 1 - Kullanıcı metin görünümünü seçer seçmez yer tutucunun yok olmasını istiyorsanız:

Önce UITextView, yer tutucu metnini içerecek şekilde ayarlayın ve bir yer tutucu metninin görünümünü taklit etmek için açık gri bir renge ayarlayın UITextField. Ya viewDidLoadmetin görünümünün oluşturulmasında ya da üzerinde yapın.

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

Daha sonra kullanıcı metin görünümünü düzenlemeye başladığında, metin görünümü bir yer tutucu içeriyorsa (örn. Metin rengi açık gri ise) yer tutucu metni temizleyin ve kullanıcının girişini karşılamak için metin rengini siyaha ayarlayın.

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

Ardından, kullanıcı metin görünümünü düzenlemeyi bitirdiğinde ve ilk yanıtlayıcı olarak istifa ettiğinde, metin görünümü boşsa, yer tutucu metni yeniden ekleyerek ve rengini açık gri olarak ayarlayarak yer tutucusunu sıfırlayın.

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

Çözüm # 2 - Metin görünümü seçili olsa bile, yer tutucunun metin görünümü boş olduğunda gösterilmesini istiyorsanız:

İlk olarak yer tutucuyu şurada ayarlayın viewDidLoad:

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

textView.becomeFirstResponder()

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

(Not: OP, görünüm yüklenir yüklenmez metin görünümünün seçilmesini istediğinden, yukarıdaki görünümde metin görünümü seçimini dahil ettim. İstediğiniz davranış bu değilse ve görünüm yüklendiğinde metin görünümünün seçilmesini istemiyorsanız, Yukarıdaki kod yığınından son iki satırı kaldırın.)

Sonra shouldChangeTextInRange UITextViewDelegateyöntemi kullanın, şöyle:

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
}

Ayrıca textViewDidChangeSelection, kullanıcının yer tutucu görünürken imlecin konumunu değiştirmesini önlemek için de uygulayın . (Not: textViewDidChangeSelectiongörünüm yüklenmeden önce çağrılır, bu nedenle yalnızca metin görünürse metin görünümünün rengini kontrol edin):

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

5
Merhaba, görünüm denetleyicinizi textView temsilciniz olarak ayarladığınızdan emin olun . Bunu textView öğenizden viewController'ınıza bir çıkış oluşturarak gerçekleştirebilirsiniz. Sonra kullanın yourTextField.delegate = self. Bunu yapmazsanız, textViewDidBeginEditingve textViewDidEndEditingişlevleri çalışmaz.
Ujjwal-Nadhani

2
Kod derleme değil, ben bir hata yaşıyorum Cannot convert value of type 'NSRange' (aka '_NSRange') to expected argument type 'Range<String.Index>' (aka 'Range<String.CharacterView.Index>').
iPeter

4
Çözümü buldum ve revize edilmiş kodu @iPeter ekleyeceğim. Geçerli metin NSString formant: konumunda olmalıdır let currentText = textView.text as NSString?. let updatedText =Satırı şuna dönüştür let updatedText = currentText?.replacingCharacters(in: range, with: text). Son olarak, if updatedText.isEmptysatırı dönüştürün if (updatedText?.isEmpty)! {. Hile yapmalı!
Baylor Mitchell

1
@ TàTruhoada Kopyalama ve yapıştırma senaryolarını ele alma çözümünü güncelledim
Lyndsey Scott

3
@LyndseyScott ayarı textView.selectedTextRangeiçinden func textViewDidChangeSelection(_ textView: UITextView)... sonsuz bir döngüye neden olur
MikeG

229

Yüzer Yer Tutucu


Bir yer tutucu etiketi bir metin görünümünün üzerine yerleştirmek, yazı tipini ayarlamak, rengini ayarlamak ve metin görünümünün karakter sayımındaki değişiklikleri izleyerek yer tutucu görünürlüğünü yönetmek basit, güvenli ve güvenilirdir.

Hızlı 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: Aynen, hariç: italicSystemFontOfSize(textView.font.pointSize),UIColor.lightGrayColor



19
Bu yöntem inkar edilemez bulduğum en basit ve en az hata eğilimli. Muhteşem.
David

6
İyi bir yöntem ama yer tutucu metin çok uzunsa etiket metni sınırların dışına çıkabilir ..
Aks

5
Kullanımı basit ve mevcut davranışlarla güzel bir şekilde bütünleşiyor. Yer tutucu mesaj yine de bu kadar ayrıntılı olmamalı, ancak satırları 0 olarak ayarlamak bu konuyla ilgilenmez mi?
Tommie C.Kasım

2
Genellikle bu yöntemi tercih ederim, ancak imleç sol yerine yer tutucunun üzerinde ortalanacak şekilde metnin merkeze hizalanması sorunludur.
blwinters

1
@blwinters - Bu gerçekten alışılmadık bir köşe durumu olurdu değil mi? Ancak, bu durumda çok satırlı bir giriş alanı olduğunu varsayarsak (bunu varsaymak zorundayım), yer tutucu metni imlecin biraz uzağına taşımak için dikey uzaklık hesaplamasını ayarlayamaz mıydınız?
clearlight

35

KMPlaceholderTextView kitaplığını kullanmanızı kesinlikle öneririz . Kullanımı çok basit.


1
Bu, en kolay çözümdür (UILabels eklemeyi veya özel delege işleri yapmayı içermez). Kutudan çıkar çıkmaz çalışır.
HixField

İşe yaramalı. Yazar Swift 3.0+ desteklediğini söyledi
t4nhpt

27

Swift:

Metin görünümünüzü programlı olarak veya Arayüz Oluşturucu ile ekleyin, sonuncusu ise çıkışı oluşturun:

@IBOutlet weak var yourTextView: UITextView!

Lütfen temsilci ekleyin (UITextViewDelegate):

class ViewController: UIViewController, UITextViewDelegate {

ViewDidLoad yönteminde aşağıdakileri ekleyin:

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

Şimdi sihirli kısmı tanıtayım, bu işlevi ekleyin:

func textViewDidBeginEditing(_ textView: UITextView) {

    if yourTextView.textColor == UIColor.lightGray {
        yourTextView.text = ""
        yourTextView.textColor = UIColor.black
    }
}

Bunun düzenleme başladığında yürütüleceğini unutmayın, orada color özelliğini kullanarak durumu bildirmek için koşulları kontrol edeceğiz. Metnin nili olarak ayarlanması önerilmez. Bundan hemen sonra metin rengini istenen, bu durumda siyah olarak ayarladık.

Şimdi bu işlevi de ekleyin:

func textViewDidEndEditing(_ textView: UITextView) {

    if yourTextView.text == "" {

        yourTextView.text = "Placeholder text ..."
        yourTextView.textColor = UIColor.lightGray
    }
}

Israr edeyim, karşılaştırmayın nil, ben zaten denedim ve işe yaramaz. Daha sonra değerleri tekrar yer tutucu stiline ayarlıyoruz ve check-in için bir koşul olduğu için rengi tekrar yer tutucu rengine ayarlıyoruz textViewDidBeginEditing.


16

Bu Uzantıyı Kullan, bu, UITextView'da yer tutucu ayarlamanın en iyi yoludur. Ancak, TextView'a delegeler eklediğinizden emin olun. Yer tutucuyu şu şekilde ayarlayabilirsiniz: -

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
    }
}

1
Takılar gibi çalıştı !! Çok teşekkür ederim ! :)
Nahid Raihan

Sevgili Sevgili, tüm iyi
Sandip Gill

15

Kimsenin bahsetmediğine şaşırdım NSTextStorageDelegate. UITextViewDelegateyöntemleri yalnızca kullanıcı etkileşimi tarafından tetiklenir, ancak programlı olarak tetiklenmez. Örneğin, bir metin görünümünün textözelliğini programlı olarak ayarladığınızda, temsilci yöntemleri çağrılmayacağından yer tutucunun görünürlüğünü kendiniz ayarlamanız gerekir.

Ancak, NSTextStorageDelegate's textStorage(_:didProcessEditing:range:changeInLength:)yöntemi ile, programlı olarak yapılsa bile metinde yapılan herhangi bir değişiklik size bildirilir. Sadece şu şekilde atayın:

textView.textStorage.delegate = self

(İçinde UITextView, bu temsilci özelliği nilvarsayılan olarak, bu nedenle herhangi bir varsayılan davranışı etkilemez.)

İle birleştirin UILabel, kolayca bütün sarar gösteriyor @clearlight tekniği UITextView'nin placeholderbir uzantısı haline uygulanmasını.

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
        }
    }

}

Özel (iç içe) sınıfın çağrıldığını unutmayın PlaceholderLabel. Hiç bir uygulaması yoktur, ancak tagözelliği kullanmaktan çok daha 'swifty' olan yer tutucu etiketi tanımlamamıza yardımcı olur .

Bu yaklaşımla, delegesini UITextViewbaşkasına atayabilirsiniz .

Metin görünümlerinizin sınıflarını bile değiştirmeniz gerekmez. Uzantıları eklemeniz yeterlidir UITextView; hatta Arayüz Oluşturucu'da bile projenizdeki her yere bir yer tutucu dizesi atayabilirsiniz .

placeholderColorAçıklık nedenleriyle bir mülkün uygulanmasını dışarıda bıraktım , ancak benzer bir hesaplanmış değişkene sahip birkaç satır daha uygulanabilir placeholder.


Çok zarif bir çözüm. Onu seviyorum.
Dave Batton

textView.textStorage.delegate = selfbu bir görünüm denetleyicisindeki bu görünüm denetleyicisini bağlamamızı gerektirir NSTextStorageDelegate. Gerçekten gerektirir mi?
Hemang

Basit ve cazibe gibi çalışır. Bu cevap kabul edilmelidir
Qaiser Abbas

@ Hemanga NSTextStorageDelegategörünüm denetleyicisi değil, metin görünümünün kendisidir .
yesleon

14

Bunu iki farklı metin görünümü kullanarak yaptım:

  1. Arka planda bir yer tutucu olarak kullanılan bir.
  2. Kullanıcının gerçekten girdiği ön planda (saydam bir arka planla) bir tane.

Fikir, kullanıcı ön plan görünümünde bir şeyler yazmaya başladığında, arka plandaki yer tutucunun kaybolması (ve kullanıcının her şeyi silmesi durumunda yeniden görünmesi). Dolayısıyla, tek satırlık metin alanı için bir yer tutucu gibi davranır.

İşte bunun için kullandığım kod. DescriptionField öğesinin kullanıcının yazdığı alan ve descriptionPlaceholder öğesinin arka plandaki alan olduğunu unutmayın.

func textViewDidChange(descriptionField: UITextView) {
    if descriptionField.text.isEmpty == false {
        descriptionPlaceholder.text = ""
    } else {
        descriptionPlaceholder.text = descriptionPlaceholderText
    }
}

1
Bu şekilde biraz acayip ama çok kolay ve uzak ve tam olarak istediğiniz sonuçları üretir. İyi fikir
William T.

9

Buradaki bazı harika önerilere dayanarak, aşağıdaki hafif, Interface-Builder uyumlu alt sınıfı bir araya getirebildim UITextView:

  • Aynı şekilde stilize edilmiş, yapılandırılabilir yer tutucu metin içerir UITextField.
  • Herhangi bir ek alt görünüm veya kısıtlama gerektirmez.
  • ViewController'dan herhangi bir temsilci seçme veya başka bir davranış gerektirmez.
  • Herhangi bir bildirim gerektirmez.
  • Metnin, alanın textözelliğine bakarak herhangi bir dış sınıftan tamamen ayrılmasını sağlar .

Herhangi bir iyileştirme önerisi, özellikle iOS'un yer tutucu rengini zor kodlamak yerine programlı olarak çekmenin herhangi bir yolu varsa, bekliyoruz.

Swift v5:

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 /programming/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
    }
}

6

Görünüm yükünde SET değeri

    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()
}

6

Ben kod elverişli yapmaya çalıştı Clearlight 'ın cevabı .

extension UITextView{

    func setPlaceholder() {

        let placeholderLabel = UILabel()
        placeholderLabel.text = "Enter some text..."
        placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
        placeholderLabel.sizeToFit()
        placeholderLabel.tag = 222
        placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.isHidden = !self.text.isEmpty

        self.addSubview(placeholderLabel)
    }

    func checkPlaceholder() {
        let placeholderLabel = self.viewWithTag(222) as! UILabel
        placeholderLabel.isHidden = !self.text.isEmpty
    }

}

kullanım

override func viewDidLoad() {
    textView.delegate = self
    textView.setPlaceholder()
}

func textViewDidChange(_ textView: UITextView) {
    textView.checkPlaceholder()
}

Birkaç konu. (1) Bir UIView etiketi özellik değerini kabul eden ve 'ödünç alan' bir uzantı olarak, birisinin kendi etiket hiyerarşisinde aynı uzantıyı kullanması, uzantının kullanımından habersiz ve hata teşhisi için son derece zor bir hata oluşturma riski vardır. Bunun gibi şeyler kütüphane koduna veya uzantılarına ait değildir. (2) Arayan kişinin hala bir delege beyan etmesini gerektirir. Yüzer tutucu , kesmek önler minik ayak izi vardır, güvenli bir bahis yapar basit ve tamamen yerel.
clearlight

5

Bir çözüm daha (Swift 3):

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)
    }
}

sonuç

resim açıklamasını buraya girin


4

Benim için çalışan basit ve hızlı bir çözüm:

@IBDesignable
class PlaceHolderTextView: UITextView {

    @IBInspectable var placeholder: String = "" {
         didSet{
             updatePlaceHolder()
        }
    }

    @IBInspectable var placeholderColor: UIColor = UIColor.gray {
        didSet {
            updatePlaceHolder()
        }
    }

    private var originalTextColor = UIColor.darkText
    private var originalText: String = ""

    private func updatePlaceHolder() {

        if self.text == "" || self.text == placeholder  {

            self.text = placeholder
            self.textColor = placeholderColor
            if let color = self.textColor {

                self.originalTextColor = color
            }
            self.originalText = ""
        } else {
            self.textColor = self.originalTextColor
            self.originalText = self.text
        }

    }

    override func becomeFirstResponder() -> Bool {
        let result = super.becomeFirstResponder()
        self.text = self.originalText
        self.textColor = self.originalTextColor
        return result
    }
    override func resignFirstResponder() -> Bool {
        let result = super.resignFirstResponder()
        updatePlaceHolder()

        return result
    }
}

4

İşte bu iş için kullandığım şey.

@IBDesignable class UIPlaceholderTextView: UITextView {

    var placeholderLabel: UILabel?

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        sharedInit()
    }

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

    override func prepareForInterfaceBuilder() {
        sharedInit()
    }

    func sharedInit() {
        refreshPlaceholder()
        NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: UITextView.textDidChangeNotification, object: nil)
    }

    @IBInspectable var placeholder: String? {
        didSet {
            refreshPlaceholder()
        }
    }

    @IBInspectable var placeholderColor: UIColor? = .darkGray {
        didSet {
            refreshPlaceholder()
        }
    }

    @IBInspectable var placeholderFontSize: CGFloat = 14 {
        didSet {
            refreshPlaceholder()
        }
    }

    func refreshPlaceholder() {
        if placeholderLabel == nil {
            placeholderLabel = UILabel()
            let contentView = self.subviews.first ?? self

            contentView.addSubview(placeholderLabel!)
            placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false

            placeholderLabel?.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: textContainerInset.left + 4).isActive = true
            placeholderLabel?.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: textContainerInset.right + 4).isActive = true
            placeholderLabel?.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textContainerInset.top).isActive = true
            placeholderLabel?.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: textContainerInset.bottom)
        }
        placeholderLabel?.text = placeholder
        placeholderLabel?.textColor = placeholderColor
        placeholderLabel?.font = UIFont.systemFont(ofSize: placeholderFontSize)
    }

    @objc func textChanged() {
        if self.placeholder?.isEmpty ?? true {
            return
        }

        UIView.animate(withDuration: 0.25) {
            if self.text.isEmpty {
                self.placeholderLabel?.alpha = 1.0
            } else {
                self.placeholderLabel?.alpha = 0.0
            }
        }
    }

    override var text: String! {
        didSet {
            textChanged()
        }
    }

}

Buna benzer çeşitli yaklaşımlar olduğunu biliyorum ama bundan faydaları:

  • IB'de yer tutucu metin, yazı tipi boyutu ve renk ayarlayabilir .
  • Artık IB'de " Kaydırma Görünümünde belirsiz kaydırılabilir içerik var " uyarısı gösterilmiyor .
  • Yer tutucuyu göstermek / gizlemek için animasyon ekleyin .

3

Hızlı 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
        }
    }
}

İlk olarak kullanıcı textViewDidBeginEditing çağrısını düzenlemeye başladığında ve sonra metin gri renginin kullanıcının herhangi bir şey yazmadığı anlamına geldiğini kontrol ettikten sonra textview nil olarak ayarlayın ve kullanıcı manifatura için rengi siyah olarak değiştirin.

Kullanıcı textViewDidEndEditing düzenlemesini sonlandırdığında çağrı yapılır ve kullanıcının metin görünümünde bir şey yazıp yazmadığını kontrol eder, ardından metin "PlaceHolder" metniyle gri renk olarak ayarlanır


3

İşte bu sorunu çözme yolum ( Swift 4 ):

Fikir, farklı renkteki yer tutucuların kullanılmasına izin veren, yer tutucu boyutuna göre yeniden boyutlandırılan, bu delegatearada tüm UITextViewişlevlerin beklendiği gibi çalışmasını sağlamayacak mümkün olan en basit çözümü yapmaktı .

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) }
}

Bu harika ve basit bir çözüm.
JaredH

2

Bu sorunu neden bu kadar karmaşık hale getirenler bilmiyorum .... Oldukça basit ve basit. İşte istenen işlevselliği sağlayan bir UITextView alt sınıfı.

- (void)customInit
{
    self.contentMode = UIViewContentModeRedraw;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}

    - (void)textChanged:(NSNotification *)notification
    {
        if (notification.object == self) {
            if(self.textStorage.length != 0 || !self.textStorage.length) {
                [self setNeedsDisplay];
            }
        }
    }


    #pragma mark - Setters

    - (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font
    {
        self.placeholderText = placeholderText;
        self.placeholderTextFont = font;

    }



    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        [[UIColor lightGrayColor] setFill];

        if (self.textStorage.length != 0) {
            return;
        }

        CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView
        NSDictionary *attributes =  @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]};
        [self.placeholderText drawInRect:inset withAttributes:attributes];
    }`

FYI, biri beni dövmeden önce ... bu Swift'e çevirmek için oldukça doğrudan. Burada karmaşık bir şey yok.
TheCodingArt

2

Birden fazla metin görünümü ile çalışıyorsanız, bu benim kullanıma hazır çözümüm

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
    }
}

Çok güzel!
KevinVuD

2

Hızlı 3.1

Bu uzantı benim için iyi çalıştı: https://github.com/devxoul/UITextView-Placeholder

İşte bir kod snippet'i:

Kapsülle kurun:

pod 'UITextView+Placeholder', '~> 1.2'

Sınıfınıza aktarın

import UITextView_Placeholder

Ve placeholderönceden oluşturduğunuza özellik ekleyinUITextView

textView.placeholder = "Put some detail"

İşte bu ... İşte nasıl göründüğü (Üçüncü kutu a UITextView) resim açıklamasını buraya girin


2

Aksine sadece bu yazı her yanıttan, UITextView does bir yer tutucu özelliği vardır. Anladığımın ötesindeki nedenlerden ötürü, sadece IB'de ortaya çıkar, şöyle:

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

Öykü tabloları kullanıyorsanız ve statik bir yer tutucu yeterliyse, özelliği denetçide ayarlayın.

Bu özelliği aşağıdaki gibi kodda da ayarlayabilirsiniz:

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

Mülkiyet olarak bu hava için Onun bulutlu, özel API aracılığıyla erişilen edilir maruz.

Bu yöntemle göndermeyi denemedim. Ama kısa süre içinde bu şekilde göndereceğim ve bu cevabı buna göre güncelleyeceğim.

GÜNCELLEME:

Apple'dan herhangi bir sorun olmadan birden fazla sürümde bu kodu gönderdim.

GÜNCELLEME: Bu yalnızca 11.2 öncesi Xcode'da çalışır


Swift 5'te myTextView, placeholder = "göz renginizi girin"
yazabilirsiniz

@ user462990 Bunun için bir belge bağlantısı sağlayabilir misiniz? Bunun doğru olduğuna inanmıyorum.
Alex Chase

üzgünüm, dox bulamadık ama test etmek gerçekten kolay ... örneğin "textField3.placeholder = language içindeki" alert.addTextField {(textField3) .JBLocalize (ifade: "adınız")}. jbLocalize, String
user462990

4
@ user462990 Sen başvuran UITextFieldDEĞİL UITextView daha dikkatli sorular / yanıtlar okuyunuz.
Alex Chase

3
Harika bir çözüm, ama benim için çalışmıyor. Her nasılsa her zaman çöküyor. Kullandığınız dağıtım hedefi, hızlı ve xCode sürümlerini belirtebilir misiniz?
T. Pasichnyk

1

İOS'ta yer tutucuyu doğrudan TextView'a eklemek için böyle bir özellik yoktur, bunun yerine textView'deki değişikliği bir etiket ekleyebilir ve gösterebilir / gizleyebilirsiniz. SWIFT 2.0 ve textviewdelegate'i uyguladığınızdan emin olun

func textViewDidChange(TextView: UITextView)
{

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

}

1

Swift - UITextView'i devralan bir sınıf yazdım ve yer tutucu olarak hareket etmek için alt görünüm olarak bir UILabel ekledim.

  import UIKit
  @IBDesignable
  class HintedTextView: UITextView {

      @IBInspectable var hintText: String = "hintText" {
          didSet{
              hintLabel.text = hintText
          }
      }

      private lazy var hintLabel: UILabel = {
          let label = UILabel()
          label.font = UIFont.systemFontOfSize(16)
          label.textColor = UIColor.lightGrayColor()
          label.translatesAutoresizingMaskIntoConstraints = false
          return label
      }()


      override init(frame: CGRect, textContainer: NSTextContainer?) {
          super.init(frame: frame, textContainer: textContainer)
          setupView()
      }

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

      override func prepareForInterfaceBuilder() {
         super.prepareForInterfaceBuilder()
         setupView()
      }

      private func setupView() {

        translatesAutoresizingMaskIntoConstraints = false
        delegate = self
        font = UIFont.systemFontOfSize(16)

        addSubview(hintLabel)

        NSLayoutConstraint.activateConstraints([

           hintLabel.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 4),
           hintLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: 8),
           hintLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4),
           hintLabel.heightAnchor.constraintEqualToConstant(30)
         ])
        }

      override func layoutSubviews() {
        super.layoutSubviews()
        setupView()
     }

}

Yer tutucuyu konumlandırmak için kısıtlamaların kullanılmasına harika bir örnek, ancak yer tutucunun ideal konumu metnin ilk karakterinin gideceği yerin hemen üzerindedir, bu nedenle metin görünümünün yazı tipine göre bu konumu hesaplamak daha iyidir çünkü metin görünümü için ayarlanan yazı tipi boyutu.
clearlight

1

@ Nerdist'in çözümünü seviyorum. Buna dayanarak, bir uzantı oluşturdum UITextView:

import Foundation
import UIKit

extension UITextView
{
  private func add(_ placeholder: UILabel) {
    for view in self.subviews {
        if let lbl = view as? UILabel  {
            if lbl.text == placeholder.text {
                lbl.removeFromSuperview()
            }
        }
    }
    self.addSubview(placeholder)
  }

  func addPlaceholder(_ placeholder: UILabel?) {
    if let ph = placeholder {
      ph.numberOfLines = 0  // support for multiple lines
      ph.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
      ph.sizeToFit()
      self.add(ph)
      ph.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
      ph.textColor = UIColor(white: 0, alpha: 0.3)
      updateVisibility(ph)
    }
  }

  func updateVisibility(_ placeHolder: UILabel?) {
    if let ph = placeHolder {
      ph.isHidden = !self.text.isEmpty
    }
  }
}

Bir ViewController sınıfında, örneğin, ben nasıl kullanırım:

class MyViewController: UIViewController, UITextViewDelegate {
  private var notePlaceholder: UILabel!
  @IBOutlet weak var txtNote: UITextView!
  ...
  // UIViewController
  override func viewDidLoad() {
    notePlaceholder = UILabel()
    notePlaceholder.text = "title\nsubtitle\nmore..."
    txtNote.addPlaceholder(notePlaceholder)
    ...
  }

  // UITextViewDelegate
  func textViewDidChange(_ textView: UITextView) {
    txtNote.updateVisbility(notePlaceholder)
    ...
  }

UITextview üzerinde yer tutucu!

resim açıklamasını buraya girin

GÜNCELLEME :

Metin görünümünün koddaki metnini değiştirmeniz durumunda, yer tutucuyu gizlemek için updateVisibitly yöntemini çağırmayı unutmayın:

txtNote.text = "something in code"
txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.

Yer tutucunun birden çok kez eklenmesini önlemek için özel bir add()işlev eklenir extension.


Orijinali iyileştirdiğiniz için tekrar teşekkür ederiz. Bu hafta sonu çok fazla zaman geçirdim, ama sonunda bulduğum EZ Placeholder aşırı değişkeninin tadını çıkaracağınızı düşünüyorum: stackoverflow.com/a/41081244/2079103 ( yer tutucu çözümleri)
clearlight

1

Swift2.2'de:

public class CustomTextView: UITextView {

private struct Constants {
    static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()

private var placeholderLabelConstraints = [NSLayoutConstraint]()

@IBInspectable public var placeholder: String = "" {
    didSet {
        placeholderLabel.text = placeholder
    }
}

@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
    didSet {
        placeholderLabel.textColor = placeholderColor
    }
}

override public var font: UIFont! {
    didSet {
        placeholderLabel.font = font
    }
}

override public var textAlignment: NSTextAlignment {
    didSet {
        placeholderLabel.textAlignment = textAlignment
    }
}

override public var text: String! {
    didSet {
        textDidChange()
    }
}

override public var attributedText: NSAttributedString! {
    didSet {
        textDidChange()
    }
}

override public var textContainerInset: UIEdgeInsets {
    didSet {
        updateConstraintsForPlaceholderLabel()
    }
}

override public init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    commonInit()
}

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

private func commonInit() {
    NSNotificationCenter.defaultCenter().addObserver(self,
                                                     selector: #selector(textDidChange),
                                                     name: UITextViewTextDidChangeNotification,
                                                     object: nil)

    placeholderLabel.font = font
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
    placeholderLabel.text = placeholder
    placeholderLabel.numberOfLines = 0
    placeholderLabel.backgroundColor = UIColor.clearColor()
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(placeholderLabel)
    updateConstraintsForPlaceholderLabel()
}

private func updateConstraintsForPlaceholderLabel() {
    var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
                                                                        options: [],
                                                                        metrics: nil,
                                                                        views: ["placeholder": placeholderLabel])
    newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(\(textContainerInset.top))-[placeholder]",
                                                                     options: [],
                                                                     metrics: nil,
                                                                     views: ["placeholder": placeholderLabel])
    newConstraints.append(NSLayoutConstraint(
        item: placeholderLabel,
        attribute: .Width,
        relatedBy: .Equal,
        toItem: self,
        attribute: .Width,
        multiplier: 1.0,
        constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
        ))
    removeConstraints(placeholderLabelConstraints)
    addConstraints(newConstraints)
    placeholderLabelConstraints = newConstraints
}

@objc private func textDidChange() {
    placeholderLabel.hidden = !text.isEmpty
}

public override func layoutSubviews() {
    super.layoutSubviews()
    placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self,
                                                        name: UITextViewTextDidChangeNotification,
                                                        object: nil)
}

}

Swift3'te:

import UIKit

sınıf CustomTextView: UITextView {

private struct Constants {
    static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()

private var placeholderLabelConstraints = [NSLayoutConstraint]()

@IBInspectable public var placeholder: String = "" {
    didSet {
        placeholderLabel.text = placeholder
    }
}

@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
    didSet {
        placeholderLabel.textColor = placeholderColor
    }
}

override public var font: UIFont! {
    didSet {
        placeholderLabel.font = font
    }
}

override public var textAlignment: NSTextAlignment {
    didSet {
        placeholderLabel.textAlignment = textAlignment
    }
}

override public var text: String! {
    didSet {
        textDidChange()
    }
}

override public var attributedText: NSAttributedString! {
    didSet {
        textDidChange()
    }
}

override public var textContainerInset: UIEdgeInsets {
    didSet {
        updateConstraintsForPlaceholderLabel()
    }
}

override public init(frame: CGRect, textContainer: NSTextContainer?) {
    super.init(frame: frame, textContainer: textContainer)
    commonInit()
}

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

private func commonInit() {
    NotificationCenter.default.addObserver(self,
                                                     selector: #selector(textDidChange),
                                                     name: NSNotification.Name.UITextViewTextDidChange,
                                                     object: nil)

    placeholderLabel.font = font
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
    placeholderLabel.text = placeholder
    placeholderLabel.numberOfLines = 0
    placeholderLabel.backgroundColor = UIColor.clear
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(placeholderLabel)
    updateConstraintsForPlaceholderLabel()
}

private func updateConstraintsForPlaceholderLabel() {
    var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
        options: [],
        metrics: nil,
        views: ["placeholder": placeholderLabel])
    newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|-(\(textContainerInset.top))-[placeholder]",
        options: [],
        metrics: nil,
        views: ["placeholder": placeholderLabel])
    newConstraints.append(NSLayoutConstraint(
        item: placeholderLabel,
        attribute: .width,
        relatedBy: .equal,
        toItem: self,
        attribute: .width,
        multiplier: 1.0,
        constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
    ))
    removeConstraints(placeholderLabelConstraints)
    addConstraints(newConstraints)
    placeholderLabelConstraints = newConstraints
}

@objc private func textDidChange() {
    placeholderLabel.isHidden = !text.isEmpty
}

public override func layoutSubviews() {
    super.layoutSubviews()
    placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}

deinit {
    NotificationCenter.default.removeObserver(self,
                                                        name: NSNotification.Name.UITextViewTextDidChange,
                                                        object: nil)
}

}

Hızlı bir şekilde bir sınıf yazdım. Gerektiğinde bu sınıfı içe aktarmanız gerekir.


Lütfen bunun hangi Swift sürümü için olduğunu
belirtin (

1

İtibar nedeniyle yorum ekleyemiyorum. @clearlight yanıtına bir temsilci daha ekleyin.

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

İhtiyaç var

çünkü textViewDidChangeilk defa çağrılmıyor


1

hayır metin görünümü için kullanılabilir yer tutucu yok. kullanıcı metin görünümüne girdiğinde üstüne etiket koymanız, ardından gizlemeniz veya kullanıcı tüm değerleri kaldırdığında varsayılan değere ayarlamanız gerekir.


1

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
    }
	


1

Düzenleme tamamlandıktan sonra yer tutucu metnimin yeniden görünmesi için kuyruk göndermem gerekiyordu.

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"
        }
    }
}

Bu değerin kullanıcının yazdığı değer olmasını istiyorsam son satır yerine ne yazarım ”textView.text =” Açıklama ”?
ISS

1

Swift:

Ekle TextView @IBOutlet :

@IBOutlet weak var txtViewMessage: UITextView!

In viewWillAppearyöntemle aşağıdaki eklerim:

override func viewWillAppear(_ animated: Bool)
{
    super.viewWillAppear(animated)

    txtViewMessage.delegate = self    // Give TextViewMessage delegate Method

    txtViewMessage.text = "Place Holder Name"
    txtViewMessage.textColor = UIColor.lightGray

}

Lütfen DelegateKullanma uzantısını ekleyin (UITextViewDelegate):

// MARK: - UITextViewDelegate
extension ViewController: UITextViewDelegate
{

    func textViewDidBeginEditing(_ textView: UITextView)
    {

        if !txtViewMessage.text!.isEmpty && txtViewMessage.text! == "Place Holder Name"
        {
            txtViewMessage.text = ""
            txtViewMessage.textColor = UIColor.black
        }
    }

    func textViewDidEndEditing(_ textView: UITextView)
    {

        if txtViewMessage.text.isEmpty
        {
            txtViewMessage.text = "Place Holder Name"
            txtViewMessage.textColor = UIColor.lightGray
        }
    }
}

1

Bizim çözüm UITextView textve ile mucking önlertextColor bir karakter sayacını kullanışlı olan özellikleriyle .

Basit:

1) UITextViewStoryboard'da master ile aynı özelliklere sahip bir kukla oluşturunUITextView . Sahte metne yer tutucu metin atayın.

2) İkisinin üst, sol ve sağ kenarlarını hizalayın UITextViews.

3) Kukla ustanın arkasına yerleştirin.

4) Geçersiz kılın textViewDidChange(textView:) Master'ın temsilci işlevini master'ın 0 karakteri varsa kukla gösterin. Aksi takdirde, efendiyi gösterin.

Bu, her ikisinin UITextViewsde şeffaf arka planı olduğunu varsayar . Yapmazlarsa, kukla 0 karakter olduğunda üstüne yerleştirin ve> 0 karakter olduğunda altına itin. Ayrıca, imlecin sağa uygun olduğundan emin olmak için yanıtlayanları değiştirmeniz gerekir UITextView.


1

Swift 4, 4.2 ve 5

[![@IBOutlet var detailTextView: UITextView!

override func viewDidLoad() {
        super.viewDidLoad()
        detailTextView.delegate = self
}

extension ContactUsViewController : UITextViewDelegate {

    public func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == "Write your message here..." {
            detailTextView.text = ""
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.86)

        }
        textView.becomeFirstResponder()
    }

    public func textViewDidEndEditing(_ textView: UITextView) {

        if textView.text == "" {
            detailTextView.text = "Write your message here..."
            detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.30)
        }
        textView.resignFirstResponder()
    }
[![}][1]][1]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.