Как добавить placeholder в UITextView на Swift: полный гайд

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему UITextView не имеет встроенного placeholder и как это обойти

Каждый iOS-разработчик, который хоть раз работал с UITextView, сталкивался с одной и той же проблемой: в отличие от UITextField, у UITextView нет встроенного свойства placeholder. Вы создаёте многострочное поле для ввода текста, запускаете приложение — и видите пустой белый прямоугольник. Пользователь не понимает, что туда нужно вводить, а дизайнер негодует.

Почему Apple не добавила это свойство? Исторически UITextView позиционировался как элемент для отображения и редактирования больших объёмов текста (например, заметок или писем), а не как поле ввода с подсказкой. Но времена изменились: сегодня мы используем UITextView для комментариев, описаний, биографий — везде, где нужен placeholder.

В этой статье мы разберём 3 проверенных способа добавить placeholder text inside UITextView in Swift. Вы узнаете, как сделать это через UILabel, через атрибуты NSAttributedString и через создание собственного подкласса. Поехали!

Способ 1: Классический UILabel поверх UITextView

Самый простой и понятный способ — разместить UILabel поверх UITextView и управлять его видимостью. Этот метод идеален для новичков и для проектов, где не требуется сложная кастомизация.

Как это работает

Вы добавляете UILabel как дочерний элемент UITextView, задаёте ему текст placeholder и скрываете, когда пользователь начинает печатать. Вот пошаговый пример:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {
    
    @IBOutlet weak var textView: UITextView!
    let placeholderLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        setupPlaceholder()
    }
    
    func setupPlaceholder() {
        placeholderLabel.text = "Введите ваш комментарий..."
        placeholderLabel.font = UIFont.systemFont(ofSize: 16)
        placeholderLabel.textColor = UIColor.lightGray
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        textView.addSubview(placeholderLabel)
        
        NSLayoutConstraint.activate([
            placeholderLabel.topAnchor.constraint(equalTo: textView.topAnchor, constant: 8),
            placeholderLabel.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: 5),
            placeholderLabel.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: -5)
        ])
    }
    
    func textViewDidChange(_ textView: UITextView) {
        placeholderLabel.isHidden = !textView.text.isEmpty
    }
}

Важно: не забудьте установить делегат UITextViewDelegate и реализовать метод textViewDidChange. Если вы используете SwiftUI, подход будет другим — там используется модификатор .overlay.

Плюсы и минусы

  • Плюсы: простота, легкость в понимании, работает на любой версии iOS.
  • Минусы: нужно следить за констрейнтами, если у textview меняются insets. Также не сработает, если textview имеет NSAttributedString с разными выравниваниями.

Способ 2: Placeholder через NSAttributedString

Более элегантный способ — использовать атрибуты строки. Идея в том, что вы показываете placeholder как атрибутированный текст с серым цветом, а когда пользователь начинает ввод — заменяете его на обычный текст.

Этот метод особенно полезен, если вы работаете с UITextView в Swift и не хотите заморачиваться с дополнительными вьюхами.

Реализация

import UIKit

class ViewController: UIViewController, UITextViewDelegate {
    
    @IBOutlet weak var textView: UITextView!
    let placeholderText = "Напишите что-нибудь..."
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
        showPlaceholder()
    }
    
    func showPlaceholder() {
        textView.text = placeholderText
        textView.textColor = UIColor.lightGray
    }
    
    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.text == placeholderText && textView.textColor == UIColor.lightGray {
            textView.text = ""
            textView.textColor = UIColor.black
        }
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.isEmpty {
            showPlaceholder()
        }
    }
}

Обратите внимание: мы проверяем не только текст, но и цвет. Почему? Потому что пользователь мог ввести точно такой же текст, как placeholder — и тогда мы бы ошибочно очистили поле.

Ловушка: что если пользователь скопирует текст placeholder?

Да, это реальный кейс. Если пользователь введёт слово "Напишите что-нибудь..." чёрным цветом, наш код решит, что это placeholder. Решение: используйте отдельную булеву переменную isShowingPlaceholder для отслеживания состояния.

Способ 3: Создание подкласса UITextView с placeholder

Для продакшн-проектов лучше всего создать собственный подкласс UITextView. Это даёт максимальную гибкость и переиспользуемость. Вы один раз пишете класс, а потом используете его во всём проекте.

Полный код подкласса

import UIKit

class PlaceholderTextView: UITextView {
    
    var placeholder: String = "Placeholder" {
        didSet {
            placeholderLabel.text = placeholder
            setNeedsLayout()
        }
    }
    
    var placeholderColor: UIColor = UIColor.lightGray {
        didSet {
            placeholderLabel.textColor = placeholderColor
        }
    }
    
    private let placeholderLabel = UILabel()
    
    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    
    private func setup() {
        placeholderLabel.text = placeholder
        placeholderLabel.textColor = placeholderColor
        placeholderLabel.font = font ?? UIFont.systemFont(ofSize: 16)
        placeholderLabel.numberOfLines = 0
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(placeholderLabel)
        
        NSLayoutConstraint.activate([
            placeholderLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8),
            placeholderLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 5),
            placeholderLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -5)
        ])
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(textChanged),
                                               name: UITextView.textDidChangeNotification,
                                               object: nil)
    }
    
    @objc private func textChanged() {
        placeholderLabel.isHidden = !text.isEmpty
    }
    
    override var text: String! {
        didSet {
            textChanged()
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

Как использовать в коде

let textView = PlaceholderTextView()
textView.placeholder = "Ваше сообщение..."
textView.placeholderColor = UIColor.systemGray3
textView.frame = CGRect(x: 20, y: 100, width: 300, height: 150)
view.addSubview(textView)

                
                

Блоги

Рекомендаций по книгам