Как создать атрибутированную строку (NSAttributedString) в Swift?
Правильное создание NSAttributedString в Swift
Проблема вашего кода в том, что NSAttributedString является неизменяемым (immutable) типом. Вы не можете изменить его после создания через let. Для изменения атрибутов нужно использовать изменяемую версию — NSMutableAttributedString. Вот правильный подход:
import UIKit
// 1. Создаем изменяемую атрибутированную строку
let attributedString = NSMutableAttributedString(string: "Привет, мир!")
// 2. Добавляем атрибуты с помощью метода addAttribute
attributedString.addAttribute(.foregroundColor,
value: UIColor.red,
range: NSRange(location: 0, length: 7))
// 3. Применяем к UILabel
let label = UILabel()
label.attributedText = attributedString
Комбинирование нескольких атрибутов
Чтобы применить несколько стилей к разным частям строки, используйте несколько вызовов addAttribute. Вот пример с жирным шрифтом, цветом и подчеркиванием:
let text = "Привет, мир! Это Swift."
let attributedString = NSMutableAttributedString(string: text)
// Жирный шрифт для первого слова
let boldFont = UIFont.boldSystemFont(ofSize: 18)
attributedString.addAttribute(.font,
value: boldFont,
range: NSRange(location: 0, length: 6))
// Красный цвет для "мир"
attributedString.addAttribute(.foregroundColor,
value: UIColor.red,
range: NSRange(location: 8, length: 3))
// Подчеркивание для "Swift"
attributedString.addAttribute(.underlineStyle,
value: NSUnderlineStyle.single.rawValue,
range: NSRange(location: 17, length: 5))
// Дополнительно: меняем фон для части текста
attributedString.addAttribute(.backgroundColor,
value: UIColor.yellow,
range: NSRange(location: 0, length: 6))
label.attributedText = attributedString
Удобный способ через словарь атрибутов
Можно использовать метод setAttributes для применения сразу набора атрибутов к диапазону:
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 16),
.foregroundColor: UIColor.blue,
.underlineStyle: NSUnderlineStyle.double.rawValue
]
let range = NSRange(location: 0, length: 6)
attributedString.setAttributes(attributes, range: range)
Работа с NSRange и эмодзи
Важно: NSRange работает с UTF-16 кодировкой, поэтому для строк с эмодзи или специальными символами нужно быть осторожным. Используйте (text as NSString).range(of: "слово") для безопасного поиска:
let text = "Привет 😊 мир!"
let attributedString = NSMutableAttributedString(string: text)
if let range = text.range(of: "😊") {
let nsRange = NSRange(range, in: text)
attributedString.addAttribute(.font,
value: UIFont.systemFont(ofSize: 30),
range: nsRange)
}
Расширение для удобства
Чтобы не писать каждый раз NSRange, сделайте небольшое расширение:
extension NSMutableAttributedString {
func addAttribute(_ key: NSAttributedString.Key, value: Any, for substring: String) {
let range = (self.string as NSString).range(of: substring)
if range.location != NSNotFound {
self.addAttribute(key, value: value, range: range)
}
}
}
// Использование:
let attrStr = NSMutableAttributedString(string: "Hello World")
attrStr.addAttribute(.foregroundColor, value: UIColor.red, for: "World")
Теперь ваш код будет работать без ошибок. Главное — всегда используйте NSMutableAttributedString для изменений и не забывайте про NSRange.
Альтернативный подход: использование HTML
Если вам нужно быстро создать сложное форматирование, можно использовать HTML-строку и преобразовать её в NSAttributedString. Это удобно, когда стилизация известна из веб-источника или её проще описать в HTML:
let htmlString = """
Привет,
мир!
"""
if let data = htmlString.data(using: .utf8),
let attributedString = try? NSAttributedString(
data: data,
options: [.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil
) {
label.attributedText = attributedString
}
Использование сторонних библиотек
Для ещё более простого синтаксиса можно использовать библиотеку SwiftRichString (через CocoaPods или SPM). Пример:
import SwiftRichString
let style = Style {
$0.font = UIFont.boldSystemFont(ofSize: 16)
$0.color = UIColor.red
$0.underline = .single
}
let attributedString = "Привет, мир!".set(style: style)
label.attributedText = attributedString
Этот подход сокращает код и делает его более читаемым, особенно при работе с множеством стилей.
Ответов пока нет.
Войдите чтобы оставить ответ