Як я можу додати текст заповнювача до UITextView в Swift?


316

Я роблю програму, яка використовує UITextView. Тепер я хочу, щоб у текстовому перегляді був заповнювач, подібний до того, який ви можете встановити для текстового поля. Як би ви це зробили за допомогою Swift?


Це вікова проблема в розробці iOS з UITextView. Я написав підкласи на зразок зазначеного тут: stackoverflow.com/a/1704469/1403046 . Перевага полягає в тому, що ви все ще можете мати делегата, а також використовувати клас у декількох місцях, не потребуючи повторної реалізації логіки.
cjwirth

Як би я використовував ваш підклас, використовуючи швидкий для проекту. Використовуєте містковий файл?
StevenR

Ви можете це зробити або повторно реалізувати в Swift. Код у відповіді довший, ніж насправді має бути. Головне - показати / приховати мітку, яку ви додали в методі, про який ви отримуєте повідомлення, коли текст змінюється.
cjwirth

Ви можете використовувати зразок UIFloatLabelTextView від GitHub. Це заповнення позиції зверху під час написання. Дійсно цікавий! github.com/ArtSabintsev/UIFloatLabelTextView
Jayprakash Dubey

2
Чесно кажучи, найпростіший спосіб досягти цього - це мати спеціальний textView і просто додати текст-заповнювач, який малюється на textView, коли немає тексту .... Коли-небудь інша відповідь поки що була набагато складнішою версією цього, що передбачає проблематичність. управління державою (включаючи помилкові позитиви щодо того, коли текст повинен / не повинен / не існує)
TheCodingArt

Відповіді:


649

Оновлено для Swift 4

UITextViewне властиво властивості заповнення, тому вам доведеться створювати та маніпулювати одним програмно за допомогою UITextViewDelegateметодів. Я рекомендую використовувати або рішення №1 або №2 нижче, залежно від бажаної поведінки.

Примітка. Для будь-якого рішення додайте UITextViewDelegateдо класу та встановіть textView.delegate = selfвикористання методів делегування тексту подання тексту.


Рішення №1 - Якщо ви хочете, щоб заповнювач заповнення зник, як тільки користувач вибере перегляд тексту:

Спочатку встановіть, що UITextViewмістить текст заповнення, і встановіть його на світло-сірий колір, щоб імітувати зовнішній вигляд UITextFieldтексту-заповнювача. Або зробіть це в створеному viewDidLoadабо в текстовому вікні.

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

Потім, коли користувач починає редагувати текстовий вигляд, якщо у текстовому представленні міститься заповнювач (тобто якщо його колір тексту світло-сірий), очистіть текст заповнення та встановіть колір тексту чорним, щоб пристосувати користувач до запису.

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

Рішення №2 - Якщо ви хочете, щоб заповнювач місць відображався кожного разу, коли перегляд тексту порожній, навіть якщо вибрано подання тексту:

Спочатку встановіть заповнювач у полі viewDidLoad:

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

textView.becomeFirstResponder()

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

. видаліть останні два рядки з наведеного вище коду.)

Потім використовуйте shouldChangeTextInRange 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
}

А також реалізуйте, textViewDidChangeSelectionщоб запобігти користувачеві змінювати положення курсора, поки заповнений видимий заповнювач. (Примітка: textViewDidChangeSelectionвикликається перед завантаженням перегляду, тому перевіряйте колір перегляду тексту лише у тому випадку, якщо вікно видно):

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
Привіт, переконайтеся, що ви встановили контролер перегляду як делегат свого textView . Ви можете досягти цього, створивши розетку з textView до перегляду viewController. Потім використовуйте yourTextField.delegate = self. Якщо цього не зробити, функції textViewDidBeginEditingі textViewDidEndEditingфункції не працюватимуть.
Ujjwal-Nadhani

2
Код не компілюється, у мене помилка як Cannot convert value of type 'NSRange' (aka '_NSRange') to expected argument type 'Range<String.Index>' (aka 'Range<String.CharacterView.Index>').
iPeter

4
Я знайшов рішення і буду приєднувати переглянутий код @iPeter. В даний час текст повинен бути в NSString форманти: let currentText = textView.text as NSString?. Перетворіть let updatedText =рядок на let updatedText = currentText?.replacingCharacters(in: range, with: text). Нарешті, перетворіть if updatedText.isEmptyрядок у if (updatedText?.isEmpty)! {. Це повинно зробити трюк!
Бейлор Мітчелл

1
@ TàTruhoada Я оновив рішення для обробки сценаріїв копіювання та вставки
Ліндсі Скотт

3
Налаштування @LyndseyScott textView.selectedTextRangeзсередини func textViewDidChangeSelection(_ textView: UITextView)викликає нескінченну петлю ...
MikeG

229

Плаваючий заповнювач


Просте, безпечне та надійне розташування мітки заповнювача над текстовим поданням, встановлення його шрифту, кольору та керування видимістю заповнювача шляхом відстеження змін у кількості символів перегляду тексту.

Швидкий 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: Те ж саме, за винятком: italicSystemFontOfSize(textView.font.pointSize),UIColor.lightGrayColor



19
Цей метод, безперечно, найпростіший і найменш схильний до помилок я знайшов. Казкові.
Девід

6
Це хороший метод, але текст мітки може вийти зв'язаним, якщо текст заповнювача дуже довгий ..
Aks

5
Простий у використанні та добре поєднується з існуючою поведінкою. Повідомлення про заповнення місця все одно не повинно бути настільки багатослівним, але чи не встановлення рядків на 0 буде вирішувати цю проблему?
Tommie C.

2
Як правило, я віддаю перевагу цьому методу, хоча це проблематично, якщо текст вирівняний по центру, оскільки курсор буде розташований у центрі вгорі заповнювача замість ліворуч від нього.
blwinters

1
@blwinters - Це був би дійсно незвичний кутовий випадок, чи не так? Але якщо припустити, що в цьому випадку це багаторядкове поле введення (я маю на це припустити), чи не могли ви просто відрегулювати обчислення вертикального зміщення, щоб трохи відсунути текст заповнювача від курсору?
clearlight

35

Настійно рекомендую використовувати бібліотеку KMPlaceholderTextView . Дуже простий у використанні.


1
Це, безумовно, найпростіше рішення (не передбачає додавання UILabels або спеціальних делегатських матеріалів). Працює поза коробкою.
HixField

Це має працювати. Автор заявив, що підтримує Swift 3.0+
t4nhpt

27

Швидкий:

Додайте перегляд тексту програмно або за допомогою Interface Builder, якщо останній, створіть розетку:

@IBOutlet weak var yourTextView: UITextView!

Будь ласка, додайте делегата (UITextViewDelegate):

class ViewController: UIViewController, UITextViewDelegate {

У методі viewDidLoad додайте наступне:

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

Тепер дозвольте мені представити магічну частину, додати цю функцію:

func textViewDidBeginEditing(_ textView: UITextView) {

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

Зауважте, що це буде виконуватися кожного разу, коли розпочнеться редагування, там ми перевіримо умови, щоб повідомити про стан, використовуючи властивість кольору. Налаштування тексту nilя не рекомендую. Відразу після цього ми встановлюємо бажаний колір тексту, в даному випадку - чорний.

Тепер додайте і цю функцію:

func textViewDidEndEditing(_ textView: UITextView) {

    if yourTextView.text == "" {

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

Дозвольте наполягати, не порівнюйте nil, я вже пробував це, і це не вийшло. Потім ми повертаємо значення назад до стилю заповнення і встановлюємо колір назад до кольору заповнювача, оскільки це умова для реєстрації textViewDidBeginEditing.


16

Використовувати це розширення, це найкращий спосіб встановити заповнювач у UITextView. Але переконайтеся, що ви додали делегатів до TextView. Ви можете встановити власник місця таким чином: -

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
Працювали як принади !! Дуже тобі дякую ! :)
Nahid Raihan

Ласкаво просимо Шановні всі найкращі
Сандіп Гілл

15

Я здивований, що ніхто не згадав NSTextStorageDelegate. UITextViewDelegateМетоди методів будуть ініційовані лише взаємодією користувача, але не програмно. Наприклад, якщо програмно встановити textвластивість перегляду тексту , вам доведеться самостійно встановити видимість заповнювача, оскільки методи делегування не будуть викликані.

Однак за допомогою методу NSTextStorageDelegate's textStorage(_:didProcessEditing:range:changeInLength:)вам буде повідомлено про будь-які зміни в тексті, навіть якщо це робиться програмно. Просто призначте його так:

textView.textStorage.delegate = self

UITextViewцьому властивості делегата nilза замовчуванням, тому це не вплине на поведінку за замовчуванням.)

Об'єднайте його з UILabelтехнікою @clearlight демонструє, можна легко обернути всю UITextView«s placeholderреалізації в розширення.

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

}

Зауважте, що використання приватного (вкладеного) класу називається PlaceholderLabel. Він взагалі не має реалізації, але він дає нам спосіб ідентифікувати мітку-заповнювач, що набагато швидше, ніж використання tagвластивості.

При такому підході ви все одно можете призначити делегата UITextViewкогось іншого.

Вам навіть не потрібно змінювати класи перегляду тексту. Просто додайте розширення (і), і ви зможете призначити рядок заповнення заповнення кожному UITextViewз ваших проектів, навіть у Builder інтерфейсів.

Я залишив реалізацію placeholderColorвластивості з ясності, але вона може бути реалізована лише для кількох рядків із аналогічною обчисленою змінною placeholder.


Дуже елегантне рішення. Я це люблю.
Дейв Баттон

textView.textStorage.delegate = selfце в контролері перегляду вимагатиме від нас пов'язати цей контролер перегляду NSTextStorageDelegate. Це справді потрібно?
Hemang

Простий і працює як шарм. Це потрібно прийняти відповіддю
Кайзер Аббас

@Hemang - це сам перегляд тексту NSTextStorageDelegate, а не контролер перегляду.
yesleon

14

Я зробив це за допомогою двох різних переглядів тексту:

  1. Один на задньому плані, який використовується як заповнювач.
  2. Один на передньому плані (з прозорим фоном), який насправді вводить користувач.

Ідея полягає в тому, що після того, як користувач почне вводити матеріал у поданні переднього плану, заповнювач місця на задньому плані зникає (і знову з’являється, якщо користувач видаляє все). Таким чином, він поводиться точно як заповнювач для текстового поля для одного рядка.

Ось код, який я використав для цього. Зауважте, що опис Field - це поле, яке вводиться користувачем, а опис.

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

1
Цей спосіб трохи хакітний, але далеко і далеко найпростіший і генерує саме ті результати, які ви хочете. Гарна ідея
Вільям Т.

9

На підставі деяких чудових пропозицій тут уже вдалося зібрати наступний легкий підрозділ UITextView, сумісний з Interface-Builder , який:

  • Включає настроюваний текст-заповнювач, стилізований так, як у UITextField.
  • Не потребує додаткових підглядів чи обмежень.
  • Не вимагає делегування чи іншої поведінки від ViewController.
  • Не потребує сповіщень.
  • Зберігає, що текст повністю відокремлений від будь-яких зовнішніх класів, дивлячись на textвластивості поля .

Будь-які пропозиції щодо вдосконалення вітаються, особливо якщо є якийсь спосіб вивести колір заповнювача iOS програмно, а не жорстко кодувати його.

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

Значення SET при перегляді навантаження

    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

Я намагався зробити код зручним з Clearlight «s відповіді .

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
    }

}

використання

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

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

Пару питань. (1) Оскільки розширення, яке передбачає і "запозичує" значення властивості тегу UIView, існує ризик, що хтось може використати один і той же тег у власній ієрархії перегляду, не знаючи про використання розширення, що створює надзвичайно складно діагностувати помилку. Такі речі не належать до бібліотечного коду чи розширень. (2) Це все ще вимагає, щоб абонент оголосив делегата. Плаваючий Заполнитель уникає хакі, має крихітний слід, просто і повністю локальні, що робить його безпечної ставкою.
clearlight

5

Ще одне рішення (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)
    }
}

результат

введіть тут опис зображення


4

Просте і швидке рішення, яке працює для мене:

@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

Ось що я використовую для цієї роботи.

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

}

Я знаю, що існує декілька подібних підходів, але переваги цього:

  • Можна встановити текст, розмір шрифту та колір заповнювача у IB .
  • Більше не відображається попередження про " Перегляд прокрутки має неоднозначний прокручуваний вміст " у IB.
  • Додайте анімацію для показу / приховування заповнювача.

3

Швидкий 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
        }
    }
}

Спочатку, коли користувач починає редагувати виклик textViewDidBeginEditing, а потім перевіряє, чи колір сірого тексту означає, що користувач нічого не написав, потім встановіть як textview нуль і змініть колір на чорний для текстових повідомлень користувача.

Коли користувач завершує редагування textViewDidEndEditing, це дзвінок і перевірте, чи користувач нічого не пише в перегляді тексту, тоді текст встановлюється як сірий колір з текстом "PlaceHolder"


3

Ось мій спосіб вирішення цієї проблеми ( Swift 4 ):

Ідея полягала в тому, щоб зробити найпростіше можливе рішення, яке дозволяє використовувати заповнювачі різного кольору, змінюючи розміри розмірів, не замінюючи delegateтим часом, підтримуючи роботу всіх UITextViewфункцій, як очікувалося.

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

Це чудове і просте рішення.
JaredH

2

Я не знаю, чому люди надто ускладнюють цю проблему .... Це досить прямо і просто. Ось підклас UITextView, який забезпечує потрібну функціональність.

- (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, перш ніж хтось бив мене до цього ... це досить прямо в перекладі на Свіфт. Тут нічого складного.
TheCodingArt

2

Це моє готове до використання рішення, якщо ви працюєте з кількома переглядами тексту

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

Це дуже гарно!
KevinVuD

2

Швидкий 3.1

Це розширення добре працювало для мене: https://github.com/devxoul/UITextView-Placeholder

Ось фрагмент коду:

Встановіть його через pod:

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

Імпортуйте його у свій клас

import UITextView_Placeholder

І додайте placeholder властивість до вже створеногоUITextView

textView.placeholder = "Put some detail"

Ось це ... Ось як це виглядає (Третє поле - це UITextView) введіть тут опис зображення


2

В відміну від майже кожен відповідь на цей пост, UITextView робить мають властивість заповнювач. З причин, що не відповідають моєму розумінню, вона виявляється лише в IB, як такому:

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

Отже, якщо ви використовуєте мовленнєві дошки і статичного заповнювача заповнюється, просто встановіть властивість інспектору.

Ви також можете встановити цю властивість у такому коді:

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

Його мутний , як до погоди це доступ через приватний API, як властивість є піддається.

Я не намагався надсилати цей метод. Але я буду подавати цей шлях найближчим часом і відповідним чином оновлю цю відповідь.

ОНОВЛЕННЯ:

Я постачав цей код у декількох випусках, без проблем від Apple.

ОНОВЛЕННЯ: Це працюватиме лише в Xcode до 11.2


у Swift 5 ви можете написати myTextView, placeholder = "введіть свій колір очей"
user462990

@ user462990 Чи можете ви надати посилання на документацію для цього? Я не вірю, що це точно.
Алекс Чейз

вибачте, не знайшли dox, але це дуже легко перевірити ... наприклад, "alarm.addTextField {(textField3) у textField3.placeholder = language.JBLocalize (фраза:" yourName ")}. jbLocalize - це менеджер перекладів, який повертає Рядок
user462990

3
@ user462990 Ви посилаєтесь UITextFieldНЕ, UITextView будь ласка уважніше читайте питання / відповіді.
Алекс Чейз

3
Чудове рішення, але не працює для мене. Якось завжди випадає. Не могли б ви вказати цілі розгортання, швидку та xCode версію, яку ви використовуєте?
Т. Пасічник

1

Немає такої властивості в ios, щоб додавати заповнювач місця безпосередньо в TextView, скоріше ви можете додати мітку та показати / приховати зміну textView. SWIFT 2.0 і переконайтеся, що потрібно реалізувати перегляд тексту

func textViewDidChange(TextView: UITextView)
{

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

}

1

Swift - я написав клас, який успадкував UITextView, і я додав UILabel як підвід, щоб діяти як заповнювач.

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

}

Чудовий приклад використання обмежень для позиціонування заповнювача, однак ідеальне положення заповнювача знаходиться саме над тим, де збирається перший символ тексту, тому обчислення цієї позиції на основі шрифту тексту перегляду краще для цього, оскільки воно адаптується до якого розміру шрифту встановлено для перегляду тексту.
clearlight

1

Мені подобається рішення @ nerdist. На основі цього я створив розширення для 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
    }
  }
}

Наприклад, у класі ViewController, як це я використовую:

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!

введіть тут опис зображення

ОНОВЛЕННЯ :

Якщо ви зміните текст перегляду тексту в коді, не забудьте викликати метод updateVisibitly, щоб приховати заповнювач:

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

Щоб запобігти додаванню заповнювача не раз, в ньому add()додається приватна функція extension.


Ще раз дякую за ваше вдосконалення до оригіналу. Я витратив занадто багато часу на ці вихідні, але, думаю, вам сподобається екстремальний варіант EZ Placeholder, який я врешті-решт придумав: stackoverflow.com/a/41081244/2079103 (я дав вам кредит за внесок у розвиток еволюції рішення заповнення місця)
clearlight

1

У швидкому2.2:

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:

import UIKit

клас 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)
}

}

Я швидко написав клас. Вам потрібно імпортувати цей клас, коли це потрібно.


Будь ласка, згадайте, для чого це версія Swift (не працює для Swift 3)
clearlight

1

Я не можу додати коментар через репутацію. додайте ще одну необхідність делегата у відповідь @clearlight.

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

є потреба

тому що textViewDidChangeназивається не вперше


1

ні, немає жодного заповнювача заповнення для перегляду тексту. ви повинні поставити ярлик над ним, коли користувач вводить текст, а потім приховати його або встановити за замовчуванням, коли користувач вводить видалити всі значення.


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

Мені довелося відправляти чергу, щоб знову з'явити текст мій заповнювача, коли редагування було завершено.

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

Що я ввожу замість останнього рядка "textView.text =" Опис ", якщо я хочу, щоб це значення було тим, що вводить користувач?
ISS

1

Швидкий:

Додайте TextView @IBOutlet:

@IBOutlet weak var txtViewMessage: UITextView!

У viewWillAppearметоді додайте наступне:

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

    txtViewMessage.delegate = self    // Give TextViewMessage delegate Method

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

}

Додайте Delegateрозширення Використання (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

Наше рішення дозволяє уникнути спілкування із властивостями UITextView textта textColorвластивостями, що зручно, якщо ви підтримуєте лічильник символів.

Це просто:

1) Створіть манекенник UITextViewу дошці розгортки з тими ж властивостями, що і майстер UITextView. Призначте текст заповнення тексту манекена.

2) Вирівняйте верхній, лівий і правий краї двох UITextViews.

3) Помістіть пустушку за майстром.

4) Замініть функцію textViewDidChange(textView:)делегата майстра і покажіть манекен, якщо у майстра є 0 символів. В іншому випадку покажіть майстру.

Це передбачає, що обидва UITextViewsмають прозорі фони. Якщо цього немає, покладіть манекен вгору, коли є 0 символів, і натисніть його внизу, коли є> 0 символів. Вам також доведеться поміняти відповіді, щоб переконатися, що курсор слідує праворуч UITextView.


1

Швидкі 4, 4.2 та 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]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.