The code below renders the following text in both Android Views and in Jetpack Compose UI.
Contact our team on 555 555 555 Opt 3 to activate.
The code below renders the following text in both Android Views and in Jetpack Compose UI.
Contact our team on 555 555 555 Opt 3 to activate.
| @Composable | |
| fun annotatedStringResource(@StringRes id: Int, vararg formatArgs: Any): AnnotatedString { | |
| val resources = LocalContext.current.resources | |
| return remember(id) { | |
| val text = resources.getText(id, *formatArgs) | |
| spannableStringToAnnotatedString(text) | |
| } | |
| } | |
| @Composable | |
| fun annotatedStringResource(@StringRes id: Int): AnnotatedString { | |
| val resources = LocalContext.current.resources | |
| return remember(id) { | |
| val text = resources.getText(id) | |
| spannableStringToAnnotatedString(text) | |
| } | |
| } | |
| private fun spannableStringToAnnotatedString(text: CharSequence): AnnotatedString { | |
| return if (text is Spanned) { | |
| val spanStyles = mutableListOf<AnnotatedString.Range<SpanStyle>>() | |
| spanStyles.addAll(text.getSpans(0, text.length, UnderlineSpan::class.java).map { | |
| AnnotatedString.Range( | |
| SpanStyle(textDecoration = TextDecoration.Underline), | |
| text.getSpanStart(it), | |
| text.getSpanEnd(it) | |
| ) | |
| }) | |
| spanStyles.addAll(text.getSpans(0, text.length, StyleSpan::class.java).map { | |
| AnnotatedString.Range( | |
| SpanStyle(fontWeight = FontWeight.Bold), | |
| text.getSpanStart(it), | |
| text.getSpanEnd(it) | |
| ) | |
| }) | |
| AnnotatedString(text.toString(), spanStyles = spanStyles) | |
| } else { | |
| AnnotatedString(text.toString()) | |
| } | |
| } |
| <string name="launch_awaiting_instructions">Contact <b>our</b> team on %1$s to activate.</string> | |
| <string name="support_contact_phone_number"><b>555 555 555</b> Opt <b>3</b></string> |
| fun Spanned.toHtmlWithoutParagraphs(): String { | |
| return HtmlCompat.toHtml(this, HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE) | |
| .substringAfter("<p dir=\"ltr\">").substringBeforeLast("</p>") | |
| } | |
| fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence { | |
| val escapedArgs = args.map { | |
| if (it is Spanned) it.toHtmlWithoutParagraphs() else it | |
| }.toTypedArray() | |
| val resource = SpannedString(getText(id)) | |
| val htmlResource = resource.toHtmlWithoutParagraphs() | |
| val formattedHtml = String.format(htmlResource, *escapedArgs) | |
| return HtmlCompat.fromHtml(formattedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY) | |
| } |
I think the
@ReadOnlyComposableshould eliminate need forremember.