Jetpack compose bold only string placeholder
Asked Answered
M

6

18

I have a string resource like this

<string name="my_string">Fancy string with an %1$s placeholder</string>

and I would like to have this as output: "Fancy string with an amazing placeholder". Which is the string with the content of the placeholder in bold.

How can I get the desired output?

Mercator answered 9/11, 2021 at 16:57 Comment(0)
M
36

Finally I got the desired result with

val placeholder = "Amazing"

val globalText = stringResource(id = R.string.my_string, placeholder)

val start = globalText.indexOf(placeholder)
val spanStyles = listOf(
    AnnotatedString.Range(SpanStyle(fontWeight = FontWeight.Bold),
        start = start,
        end = start + placeholder.length
    )
)
Text(text = AnnotatedString(text = globalText, spanStyles = spanStyles))
Mercator answered 10/11, 2021 at 11:22 Comment(0)
S
7

Use this

    @Composable
fun MultipleStylesInText() {
    Text(
        buildAnnotatedString {
            withStyle(style = SpanStyle(color = Color.Blue)) {
                append("H")
            }
            append("ello ")

            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
                append("W")
            }
            append("orld")
        }
    )
}

output - outputImage

src - github /or/ developers

Stewpan answered 24/3, 2023 at 5:54 Comment(4)
This will make whole string bold, not just the inserted partAutodidact
ok. so you can take reference from here, \n @Composable fun MultipleStylesInText() { Text( buildAnnotatedString { withStyle(style = SpanStyle(color = Color.Blue)) { append("H") } append("ello ") withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) { append("W") } append("orld") } ) }Stewpan
Please edit your answer instead of posting improvements in the commentsAutodidact
sorry, that was a mistakeStewpan
Z
2

I came up with a slightly more flexible and reusable solution in my point of view, as the solutions quoted above are not working if we have several place holders

@Composable
fun annotateRecursively(
    placeHolderList: List<Pair<String, SpanStyle>>,
    originalText: String
): AnnotatedString {
    var annotatedString = buildAnnotatedString { append(originalText) }
    for (item in placeHolderList) {
        annotatedString = buildAnnotatedString {
            val startIndex = annotatedString.indexOf(item.first)
            val endIndex = startIndex + item.first.length
            append(annotatedString)
            addStyle(style = item.second, start = startIndex, end = endIndex)
        }
    }
    return annotatedString
}

This basically takes a list of Pair precising the placeholder and a SpanStyle (instead of a Pair it can be a custom data class if you need anything else...)

Then iterate over the list to annotate the string with the corresponding SpanStyle to their placeholder.

Zarla answered 23/3, 2023 at 13:22 Comment(0)
L
0

Based on this answer I created this compose

@Composable
fun textMultiStyle(
    originalText: String,
    customTextList: List<TextWithStyle>
): AnnotatedString {
    var annotatedString = buildAnnotatedString { append(originalText) }

    customTextList.forEach { textExcerpt ->
        annotatedString = buildAnnotatedString {
            val startIndex = annotatedString.indexOf(textExcerpt.customText)
            val endIndex = startIndex + textExcerpt.customText.length
            append(annotatedString)
            addStyle(
                style = textExcerpt.style.toSpanStyle(),
                start = startIndex,
                end = endIndex
            )
        }
    }
    return annotatedString
}

data class TextWithStyle(
    val customText: String,
    val style: TextStyle
)

@Preview(showBackground = true)
@Composable
private fun Preview() {
    Text(
        text = textMultiStyle(
            originalText = "Quero esse trecho normal, esse em negrito, esse normal e esse em negrito laranja",
            customTextList = listOf(
                TextWithStyle(
                    customText = "esse em negrito",
                    style = MDSTextStyle.paragraph5
                ),
                TextWithStyle(
                    customText = "esse em negrito laranja",
                    style = MDSTextStyle.paragraph5.copy(color = PrimaryPure)
                ),
            )
        ),
        style = MDSTextStyle.paragraph4
    )
}

Output:

out

Lim answered 11/4, 2023 at 10:10 Comment(0)
T
-1

Assuming that you are displaying this in a Text composable, do this. Make sure to include a backslash before the $ character:

Row(modifier = Modifier.wrapContentWidth()) {
    val s = LocalContext.current.getString(R.string.my_string)
    val p = s.indexOf("%1\$s")
    Text(s.substring(0, p))
    Text("amazing", fontWeight = FontWeight.Bold)
    Text(s.substring(p + 4))
}
Tale answered 9/11, 2021 at 17:16 Comment(2)
I cannot modify the string resourceMercator
You didn't indicate that you could not modify the resource. You also didn't indicate how this text is being displayed. I'll assume it's with a Text composable. I updated my solution above.Tale
L
-1

Previous comments are too complicated. It's enough to use html tags in your string resource:

<string name="my_string">Fancy string with an <b>amazing</b> <i>placeholder</i></string>

If you are use Composable - you can use buildAnnotatedString for some cases. Documentation here

Text(
        buildAnnotatedString {
            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
                append("W")
            }
            append("orld")
        }
    )
Liberal answered 20/7, 2022 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.