Styled Texts for Android (Replaceable and Localizable)

Styled Texts can effect your UI/UX dramatically if used wisely but makes developer’s life harder. While developing UI with styled texts, Localization is the most crucial factor to consider. When you want to translate one language to another, word positions will be different most of the time. So, if you want to make bold a specific word in the text, the word’s position must be calculated dynamically.
Previously, In Android Development, HTML formatting (which is Deprecated now in my opinion) was used pretty heavily. These formatting looks like this below.
People blame <b><i>machines</i></b> very often for, for it\’s oh, the machine\’s fault, how can it be the machine\’s fault?
But as we all know that, HTML formatting is not suitable for all text changes such as changing custom font or inserting icon.
So, I’ve started to use Annotation for this complex scenario. It basically uses the tags inside of the string to get dynamically computed text block area.
<string name="thanks_message"><annotation font="publicsans_medium">Thanks</annotation> <annotation replacement="user_name">usernamePlaceholder</annotation>for reading my blog post.</string>
After creating string in xml, we need to find where the “Thanks” and “usernamePlaceholder” are. After that, change font of “Thanks” and replace “usernamePlaceholder” with real username. With annotations, we can find these blocks and use Android Spans to make changes that we need.
You may want to use the library. There’re examples on the README.md of library.
If you don’t want to add another dependency to your project, I’m sharing the basic method and examples here below.
You can access CustomTypefaceSpan class here.
Examples without library:
bold/italic/underline/bolditalic:

-- .xml
<string name="thanks_message"><annotation type="bold">Thanks</annotation> for reading through the documentation.</string>-- .kt
thanksMessageTextView.text = context.getXmlStyledString(R.string.thanks_message)
font:

-- .xml
<string name="thanks_message"><annotation font="publicsans_medium">Thanks</annotation> for reading through the documentation.</string>-- .kt
thanksMessageTextView.text = context.getXmlStyledString(R.string.thanks_message)
color:

-- .xml
<string name="thanks_message"><annotation custom="thanks_color">Thanks</annotation> for reading through the documentation.</string>-- .kt
val thanksColor = ContextCompat.getColor(context, R.color.purple)
thanksMessageTextView.text = context.getXmlStyledString(
stringResId = R.string.thanks_message,
customAnnotations = listOf("thanks_color, ForegroundColorSpan(thanksColor))
)
replacement:

-- .xml
<string name="thanks_message">Thanks <annotation replacement="username">usernamePlaceholder</annotation> for reading through the documentation.</string>-- .kt
val replacementList = listOf("username" to "Yumi")
thanksMessageTextView.text = context.getXmlStyledString(
stringResId = R.string.thanks_message,
replacementList = replacementList
)
custom:

-- .xml
<string name="thanks_message"><annotation custom="background_color">Thanks</annotation> <annotation custom="android_icon"> </annotation> for reading through the documentation.</annotation></string>-- .kt
val thanksBackgroundColor = ContextCompat.getColor(context, R.color.purple)val customAnnotations = listOf(
"background_color" to BackgroundColorSpan(thanksBackgroundColor),
"android_icon" to ImageSpan(context, R.drawable.ic_android)
)thanksMessageTextView.text = context.getXmlStyledString(
stringResId = R.string.thanks_message,
customAnnotations = customAnnotations
)
These spans can be used together. Nested tags are supported for both library and these methods above. If you want to make replacement value bold. It’s doable.
Thanks Florina for this awesome blog. I hope everything now looks easier and practical.
Thanks for reading. Follow me on Twitter/GitHub for upcoming blogs/libraries.