Как сделать жирный и обычный текст в одном UILabel на Swift?
Использование NSAttributedString с UIFont
Для отображения разного форматирования в одном UILabel нужно использовать NSAttributedString. Это мощный инструмент, который позволяет применять стили к отдельным частям текста. В вашем случае мы будем задавать разные шрифты для разных диапазонов символов.
Пошаговое решение
Создадим функцию, которая принимает строку и массив слов, которые нужно сделать жирными, а возвращает NSAttributedString. Вот полный пример:
import UIKit
func makeAttributedString(fullText: String, boldWords: [String], normalFont: UIFont, boldFont: UIFont) -> NSAttributedString {
let attributedString = NSMutableAttributedString(string: fullText)
// Применяем обычный шрифт ко всему тексту
attributedString.addAttribute(.font, value: normalFont, range: NSRange(location: 0, length: fullText.count))
// Для каждого слова, которое нужно сделать жирным
for word in boldWords {
// Ищем все вхождения слова в тексте
var searchRange = NSRange(location: 0, length: fullText.count)
var foundRange = NSRange()
while searchRange.location < fullText.count {
foundRange = (fullText as NSString).range(of: word, options: [], range: searchRange)
if foundRange.location != NSNotFound {
// Применяем жирный шрифт к найденному диапазону
attributedString.addAttribute(.font, value: boldFont, range: foundRange)
// Сдвигаем searchRange для поиска следующих вхождений
searchRange.location = foundRange.location + foundRange.length
searchRange.length = fullText.count - searchRange.location
} else {
break
}
}
}
return attributedString
}
// Использование:
let label = UILabel()
let normalFont = UIFont.systemFont(ofSize: 16)
let boldFont = UIFont.boldSystemFont(ofSize: 16)
let text = "Привет, мир! Это жирный текст."
let boldWords = ["мир", "жирный"]
label.attributedText = makeAttributedString(fullText: text, boldWords: boldWords, normalFont: normalFont, boldFont: boldFont)
label.numberOfLines = 0 // если текст может быть многострочным
label.sizeToFit()
Более простой способ с конкретными диапазонами
Если вы знаете точные позиции слов, можно задать диапазоны вручную:
let label = UILabel()
let attributedString = NSMutableAttributedString(string: "Привет, мир! Это жирный текст.")
// Диапазон для "мир" (с 8 по 11 символ, т.е. длина 3)
attributedString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 16), range: NSRange(location: 8, length: 3))
// Диапазон для "жирный" (с 18 по 24 символ, длина 6)
attributedString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 16), range: NSRange(location: 18, length: 6))
label.attributedText = attributedString
Важные моменты
- NSRange — это структура с полями
location(начальная позиция) иlength(длина диапазона). - Всегда используйте
NSMutableAttributedString, если нужно добавить несколько атрибутов. - Можно комбинировать разные атрибуты: цвет (
.foregroundColor), размер (.font), подчёркивание (.underlineStyle) и другие. - Для корректного подсчёта длины текста с эмодзи или специальными символами используйте
(text as NSString).length.
Этот подход полностью решает вашу задачу и позволяет гибко управлять форматированием текста в одном UILabel.
<<Альтернатива: использование вспомогательной функции с регулярными выражениями
Если вы хотите выделять жирным слова, обёрнутые в маркдаун-подобные символы (например, **жирный**), можно использовать регулярные выражения для автоматического поиска и форматирования:
import UIKit
extension UILabel {
func applyBoldMarkdown(text: String, normalFont: UIFont, boldFont: UIFont) {
let attributedString = NSMutableAttributedString(string: text)
// Регулярное выражение для поиска **текст**
let pattern = "\\*\\*(.*?)\\*\\*"
let regex = try? NSRegularExpression(pattern: pattern, options: [])
// Удаляем маркеры ** из текста и применяем жирный шрифт
if let matches = regex?.matches(in: text, options: [], range: NSRange(location: 0, length: text.count)) {
var offset = 0
for match in matches {
let fullRange = NSRange(location: match.range.location - offset, length: match.range.length)
let innerRange = NSRange(location: match.range.location + 2 - offset, length: match.range.length - 4)
attributedString.replaceCharacters(in: fullRange, with: (text as NSString).substring(with: innerRange))
attributedString.addAttribute(.font, value: boldFont, range: NSRange(location: fullRange.location, length: innerRange.length))
offset += 4 // убираем два ** с каждой стороны
}
}
// Применяем обычный шрифт ко всему, что не выделено
attributedString.addAttribute(.font, value: normalFont, range: NSRange(location: 0, length: attributedString.length))
self.attributedText = attributedString
}
}
// Использование:
let label = UILabel()
label.applyBoldMarkdown(text: "Привет, **мир**! Это **жирный** текст.",
normalFont: .systemFont(ofSize: 16),
boldFont: .boldSystemFont(ofSize: 16))
Этот подход удобен, если текст приходит с сервера или хранится в формате Markdown. Он автоматически обрабатывает все вхождения, избавляя от ручного указания диапазонов.
Ответов пока нет.
Войдите чтобы оставить ответ