kirusamma
kirusamma

Reputation: 119

Android - How can I change the color of a part of a String located in string.xml?

In my application (in Kotlin), I have a string like this in my string.xml : <string name="buy_price">Buy %1$s %2$s for %3$s %4$s</string>

Where, for example %1$s is the amount, %2$s the item name, %3$s the amount and %4$s the fiat's name.

I want to set some colors for %1$s, %2$s, %3$s, ... . But I dont know how. I have been thinking to concatenate like 5 textView which store one part of the string but it's not very clean ...

Can you help me please

Upvotes: 1

Views: 1287

Answers (3)

cactustictacs
cactustictacs

Reputation: 19622

Luiz's answer works (so I don't want the credit!) but just for anyone looking into this in general...

You can do this by wrapping your string's text in HTML tags to style it. There's two ways to display it:

  • set it to a text attribute in XML
  • set it in code using Html.fromHtml(getString(R.string.whatever))

Two tags you can use:

  • <font color="#FF0000"></font> - works in code and XML

  • <span style="color:#FF0000"></span> - works in code, not XML, possibly allows more styling. Don't add spaces in the style bit!


As Luiz says, you need to replace < characters with &lt; so getString doesn't mess up the tags before fromHtml can get to them (it does say it returns the text "stripped of styling information"). However!

  • < - broken by getString, works in XML
  • &lt; - works in code, breaks (not parsed as a tag) in XML

So basically:

  • using the string in code? Use <font> tags or style attributes, and change the opening < of tags to &lt;
  • using the string in XML? Use the <font> tag and leave the opening < alone
  • using the string in code and XML? You probably need two versions to handle the different opening tag characters!
  • using positional arguments? You're doing it in code

I haven't used data binding so I can't say for sure, but I'd assume that since you're running code (that's just defined in the XML) all the same caveats apply as running code in general.

Upvotes: 1

Xid
Xid

Reputation: 4961

Spannable implementation:

val category = "Monitor"
val item = "LG - 2562"
val currency = "Rs"
val amount = "1234"

val text = getString(R.string.buy_price, category, item, currency, amount)

val categoryColor = Color.BLUE
val categoryStart = text.indexOf(category)
val categoryEnd = categoryStart + category.length

val itemColor = Color.GREEN
val itemStart = text.indexOf(item)
val itemEnd = itemStart + item.length

val currencyColor = Color.RED
val currencyStart = text.indexOf(currency)
val currencyEnd = currencyStart + currency.length

val amountColor = Color.MAGENTA
val amountStart = text.indexOf(amount)
val amountEnd = amountStart + amount.length

textView.text = SpannableStringBuilder(text).apply {
    setSpan(
        ForegroundColorSpan(categoryColor),
        categoryStart,
        categoryEnd,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    setSpan(
        ForegroundColorSpan(itemColor),
        itemStart,
        itemEnd,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    setSpan(
        ForegroundColorSpan(currencyColor),
        currencyStart,
        currencyEnd,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
    setSpan(
        ForegroundColorSpan(amountColor),
        amountStart,
        amountEnd,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
}

Result:

enter image description here

Upvotes: 3

Luiz Fernando de Moura
Luiz Fernando de Moura

Reputation: 216

You can try with Html.fromHtml

I believe you can put on strings.xml something like:

<string name="buy_price">Buy &lt;span style='color:blue'>%1$s&lt;/span> &lt;span style='color:red'>%2$s&lt;/span> for &lt;span style='color:green'>%3$s&lt;/span> &lt;span style='color:yellow'>%4$s&lt;/span></string>

Then you call textView.text = Html.fromHtml(getString(R.string.buy_price), 0)

Obs: in strings.xml I replace < with &lt;. It's a workaround because I believe getString will try to parse html tags like <b> or <u>.

Upvotes: 2

Related Questions