У розробці для Android, HTML з'являється як Spannable, і компонент Compose Text не може прийняти Spannable як значення. Якщо ви хочете передати HTML текст як значення для компонента Text, ви можете написати розширення для Kotlin, щоб перетворити Spanned на AnnotatedString, як показано нижче.
fun Spanned.toAnnotatedString(): AnnotatedString = buildAnnotatedString {
val spanned = this@toAnnotatedString
append(spanned.toString())
getSpans(0, spanned.length, Any::class.java).forEach { span ->
val start = getSpanStart(span)
val end = getSpanEnd(span)
when (span) {
is StyleSpan -> when (span.style) {
Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)
Typeface.BOLD_ITALIC ->
addStyle(
SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic),
start,
end
)
}
is UnderlineSpan -> addStyle(
SpanStyle(textDecoration = TextDecoration.Underline),
start,
end
)
is ForegroundColorSpan -> addStyle(
SpanStyle(color = Color(span.foregroundColor)),
start,
end
)
}
}
}
Ця функція розширення для класу Spanned
створює еквівалент AnnotatedString
, переносячи стилі та їх відповідні відрізки з Spanned
у SpanStyle
Compose і додаючи їх до AnnotatedString
.
Детальне пояснення
Параметри
- Функція є розширенням класу
Spanned
, тому об'єктSpanned
, що перетворюється, доступний якthis@toAnnotatedString
.
Значення, що повертається
- Повертається
AnnotatedString
, побудований за допомогою DSL ComposebuildAnnotatedString
.
Кроки реалізації
- Ініціалізація Builder:
buildAnnotatedString {
...
}
Ініціалізується builder для AnnotatedString
. Це надає DSL для додавання тексту та застосування стилів.
2. Додати текст:
append(spanned.toString())
Звичайний текст з об'єкта Spanned
витягується та додається до AnnotatedString
.
3. Ітерація по відрізках:
getSpans(0, spanned.length, Any::class.java).forEach { span -> }
- Усі відрізки в об'єкті
Spanned
отримуються за допомогоюgetSpans
. - Ці відрізки визначають ділянки тексту з певними стилями.
- Ділянки кожного відрізка визначаються за допомогою
getSpanStart(span)
іgetSpanEnd(span)
.
4. Обробка різних типів відрізків: Кожен тип відрізка співвідноситься з відповідним SpanStyle
в Compose:
- StyleSpan:
- Представляє стиль тексту, такий як жирний, курсив або жирний-курсив.
- Відображається за допомогою
fontWeight
таfontStyle
вSpanStyle
.
is StyleSpan -> when (span.style) {
Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)
Typeface.BOLD_ITALIC -> addStyle(
SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic), start, end
)
}
- UnderlineSpan:
- Представляє підкреслений текст.
- Відображається за допомогою
textDecoration = TextDecoration.Underline
.
is UnderlineSpan -> addStyle(
SpanStyle(textDecoration = TextDecoration.Underline),
start,
end
)
- ForegroundColorSpan:
- Представляє текст з певним кольором переднього плану.
- Відображається за допомогою
color = Color(span.foregroundColor)
.
is ForegroundColorSpan -> addStyle(
SpanStyle(color = Color(span.foregroundColor)),
start,
end
)
5.
Застосування стилів до ділянок:** Для кожного типу відрізка відповідний SpanStyle
застосовується до тексту в межах ділянки відрізка [start, end)
.
Поведінка коду
- Перетворює всі підтримувані типи відрізків (
StyleSpan
,UnderlineSpan
,ForegroundColorSpan
) на їх еквіваленти в Compose. - Забезпечує збереження форматування та вигляду стильованого тексту, визначеного в оригінальному об'єкті
Spanned
.
val htmlText = """
This is bold text and this is italic text.
You can even combine both styles!
""".trimIndent()
val htmlSpannableText = HtmlCompat.fromHtml(htmlText, HtmlCompat.FROM_HTML_MODE_LEGACY)
val annotatedString = spannedText.toAnnotatedString()
Text(annotatedString)
Перекладено з: [Using html in Android Jetpack Compose Text widget](https://medium.com/@ali.alireza8002/using-html-in-android-jetpack-compose-text-widget-aa8166bfbf84)