Как изменить цвет текста placeholder в UITextField с помощью Swift?
Всем привет! Я новичок в iOS-разработке и никак не могу разобраться с одной простой, на первый взгляд, задачей.
У меня есть UITextField с placeholder'ом. Стандартный серый цвет не подходит под дизайн моего приложения. Мне нужно, чтобы текст placeholder'а был, например, синим или красным.
Я пробовал сделать так:
textField.placeholder = "Введите имя"
textField.placeholderColor = UIColor.blue // Такого свойства нет, Xcode ругается
Потом я нашел в интернете способ с NSAttributedString:
let placeholderText = NSAttributedString(string: "Введите имя", attributes: [NSAttributedString.Key.foregroundColor: UIColor.blue])
textField.attributedPlaceholder = placeholderText
Это сработало, но мне кажется, что это слишком громоздко для такой простой задачи. К тому же, если у меня много textField'ов, придется писать это для каждого.
Подскажите, пожалуйста, есть ли более простой и элегантный способ изменить цвет placeholder'а? Может быть, есть какой-то метод или свойство, которое я упустил? Или, может быть, можно создать extension для UITextField, чтобы упростить код? Буду благодарен за любые примеры и объяснения!
Использую Swift 5, iOS 13+. Заранее спасибо!
<<Решение с помощью расширения (extension) UITextField
Вы совершенно правы: каждый раз создавать NSAttributedString для каждого поля — это неудобно, особенно в больших проектах. Самый правильный и элегантный способ в Swift — добавить свойство через extension. Это позволит вам устанавливать цвет одной строкой кода.
Вот готовое решение:
import UIKit
extension UITextField {
/// Устанавливает цвет текста placeholder для UITextField
/// - Parameter color: Цвет, который нужно применить
func setPlaceholderColor(_ color: UIColor) {
// Получаем текущий текст placeholder (если он есть)
guard let placeholder = self.placeholder else {
// Если placeholder не задан, просто выходим
return
}
// Создаем атрибуты с нужным цветом
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: color
]
// Применяем атрибутированную строку
self.attributedPlaceholder = NSAttributedString(
string: placeholder,
attributes: attributes
)
}
/// Устанавливает цвет и шрифт placeholder
/// - Parameters:
/// - color: Цвет текста
/// - font: Шрифт (опционально)
func setPlaceholderColor(_ color: UIColor, font: UIFont? = nil) {
guard let placeholder = self.placeholder else { return }
var attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: color
]
// Если передан шрифт, добавляем его в атрибуты
if let font = font {
attributes[.font] = font
}
self.attributedPlaceholder = NSAttributedString(
string: placeholder,
attributes: attributes
)
}
}
Как использовать
Теперь в любом месте вашего кода вы можете написать:
// Просто меняем цвет
textField.setPlaceholderColor(.blue)
// Меняем цвет и шрифт одновременно
textField.setPlaceholderColor(.red, font: UIFont(name: "HelveticaNeue-Bold", size: 16))
// Если нужно сбросить цвет обратно на стандартный серый
textField.setPlaceholderColor(.lightGray)
Более продвинутый вариант: вычисляемое свойство
Если вы хотите, чтобы цвет можно было читать и писать как обычное свойство, можно использовать ассоциированные объекты (Associated Objects) из Objective-C runtime:
import UIKit
extension UITextField {
// Ключ для хранения цвета в runtime
private struct AssociatedKeys {
static var placeholderColor = "placeholderColor"
}
/// Цвет текста placeholder
@IBInspectable var placeholderColor: UIColor? {
get {
// Если есть attributedPlaceholder, извлекаем цвет из атрибутов
if let attributes = self.attributedPlaceholder?.attributes(
at: 0,
longestEffectiveRange: nil,
in: NSRange(location: 0, length: self.attributedPlaceholder?.length ?? 0)
) {
return attributes[.foregroundColor] as? UIColor
}
return nil
}
set {
guard let color = newValue, let placeholder = self.placeholder else { return }
let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: color]
self.attributedPlaceholder = NSAttributedString(
string: placeholder,
attributes: attributes
)
}
}
}
Теперь вы можете использовать это свойство в коде или прямо в Interface Builder (благодаря атрибуту @IBInspectable):
// В коде
textField.placeholderColor = UIColor.orange
// В Interface Builder: появится поле "Placeholder Color" в инспекторе атрибутов
Важные замечания
- Порядок важен: сначала установите обычный
placeholder(текст), а потом меняйте цвет. Или используйте метод, который проверяет наличие текста. - Не теряйте текст: если вы установите
attributedPlaceholder, а потом попытаетесь прочитатьplaceholder— он вернетnil. Поэтому в расширении мы сначала сохраняем текст черезself.placeholder. - Производительность: создание
NSAttributedString— легковесная операция, не беспокойтесь о ней.
Этот подход считается best practice в сообществе iOS-разработчиков. Он чистый, переиспользуемый и не требует сторонних библиотек.
<<Альтернативный подход: переопределение метода drawPlaceholder
Если вы не хотите использовать NSAttributedString и extension, можно переопределить метод drawPlaceholder(in:) в подклассе UITextField. Этот способ дает полный контроль над отрисовкой placeholder.
Вот пример:
import UIKit
class ColoredPlaceholderTextField: UITextField {
var placeholderColor: UIColor = .lightGray {
didSet {
// Перерисовываем placeholder при изменении цвета
setNeedsDisplay()
}
}
override func drawPlaceholder(in rect: CGRect) {
// Устанавливаем цвет и шрифт
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: placeholderColor,
.font: self.font ?? UIFont.systemFont(ofSize: 14)
]
// Рисуем текст в заданном прямоугольнике
let placeholderRect = rect.insetBy(dx: 0, dy: (rect.height - (self.font?.lineHeight ?? 0)) / 2)
self.placeholder?.draw(in: placeholderRect, withAttributes: attributes)
}
}
Плюсы:
- Работает даже если вы не устанавливали
placeholderчерез код (например, задали в сториборде). - Цвет меняется автоматически при изменении свойства.
Минусы:
- Нужно создавать подкласс и использовать его вместо обычного
UITextField. - Может потребоваться дополнительная настройка для разных состояний (например, при редактировании).
Этот метод хорош, если у вас есть кастомный текстовый компонент, который используется во всем приложении, и вы хотите инкапсулировать всю логику внутри него.
Ответов пока нет.
Войдите чтобы оставить ответ