Bold words in a string of strings.xml in Android
I have a long text in one of the strings at strings.xml. I want to make bold and change the color of some words in that text.
How can开发者_如何学Go I do it?
You could basically use html tags in your string resource like:
<resource>
<string name="styled_welcome_message">We are <b><i>so</i></b> glad to see you.</string>
</resources>
And use Html.fromHtml or use spannable, check the link I posted.
Old similar question: Is it possible to have multiple styles inside a TextView?
Use html tag inside string resources :-
<resources>
<string name="string_resource_name"><![CDATA[<b> Your text </b>]]> </string>
</resources>
And get bold text from string resources like :-
private Spanned getSpannedText(String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(text, Html.FROM_HTML_MODE_COMPACT);
} else {
return Html.fromHtml(text);
}
}
String s = format(context.getResources().getString(R.string.string_resource_name));
textView.setText(getSpannedText(s));
As David Olsson has said, you can use HTML in your string resources:
<resource>
<string name="my_string">A string with <i>actual</i> <b>formatting</b>!</string>
</resources>
Then if you use getText(R.string.my_string)
rather than getString(R.string.my_string)
you get back a CharSequence
rather than a String
that contains the formatting embedded.
In kotlin, you can create extensions functions on resources (activities|fragments |context) that will convert your string to an html span
e.g.
fun Resources.getHtmlSpannedString(@StringRes id: Int): Spanned = getString(id).toHtmlSpan()
fun Resources.getHtmlSpannedString(@StringRes id: Int, vararg formatArgs: Any): Spanned = getString(id, *formatArgs).toHtmlSpan()
fun Resources.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int): Spanned = getQuantityString(id, quantity).toHtmlSpan()
fun Resources.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int, vararg formatArgs: Any): Spanned = getQuantityString(id, quantity, *formatArgs).toHtmlSpan()
fun String.toHtmlSpan(): Spanned = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(this)
}
Usage
//your strings.xml
<string name="greeting"><![CDATA[<b>Hello %s!</b><br>]]>This is newline</string>
//in your fragment or activity
resources.getHtmlSpannedString(R.string.greeting, "World")
EDIT even more extensions
fun Context.getHtmlSpannedString(@StringRes id: Int): Spanned = getString(id).toHtmlSpan()
fun Context.getHtmlSpannedString(@StringRes id: Int, vararg formatArgs: Any): Spanned = getString(id, *formatArgs).toHtmlSpan()
fun Context.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int): Spanned = resources.getQuantityString(id, quantity).toHtmlSpan()
fun Context.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int, vararg formatArgs: Any): Spanned = resources.getQuantityString(id, quantity, *formatArgs).toHtmlSpan()
fun Activity.getHtmlSpannedString(@StringRes id: Int): Spanned = getString(id).toHtmlSpan()
fun Activity.getHtmlSpannedString(@StringRes id: Int, vararg formatArgs: Any): Spanned = getString(id, *formatArgs).toHtmlSpan()
fun Activity.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int): Spanned = resources.getQuantityString(id, quantity).toHtmlSpan()
fun Activity.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int, vararg formatArgs: Any): Spanned = resources.getQuantityString(id, quantity, *formatArgs).toHtmlSpan()
fun Fragment.getHtmlSpannedString(@StringRes id: Int): Spanned = getString(id).toHtmlSpan()
fun Fragment.getHtmlSpannedString(@StringRes id: Int, vararg formatArgs: Any): Spanned = getString(id, *formatArgs).toHtmlSpan()
fun Fragment.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int): Spanned = resources.getQuantityString(id, quantity).toHtmlSpan()
fun Fragment.getQuantityHtmlSpannedString(@PluralsRes id: Int, quantity: Int, vararg formatArgs: Any): Spanned = resources.getQuantityString(id, quantity, *formatArgs).toHtmlSpan()
Strings.xml
<string name="my_text"><Data><![CDATA[<b>Your text</b>]]></Data></string>
To set
textView.setText(Html.fromHtml(getString(R.string.activity_completed_text)));
here it's the solution for if there have any assigned values inside the string.xml file.
<string name="styled_welcome_message"><![CDATA[We are <b> %1$s </b> glad to see you.]]></string>
set in to TextView:
textView?.setText(HtmlCompat.fromHtml(getString(R.string.styled_welcome_message, "sample"), HtmlCompat.FROM_HTML_MODE_LEGACY), TextView.BufferType.SPANNABLE)
PS: don't forget to wrap your text (in String Resources) within:
<![CDATA[ YOUR TEXT HERE ]]>
Simple and Latest answer from the official Android site: source
First, you will add the string in your strings.xml
like this:
<string name="welcome">Welcome to <b>Android</b>!</string>
Here you will replace the <
before the b with <
To be like this:
<string name="welcome">Welcome to <b>Android</b>!</string>
In kotlin code you will make an extension to parse strings from html:
fun String.fromHtml(): Spanned {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// FROM_HTML_MODE_LEGACY is the behaviour that was used for versions below android N
// we are using this flag to give a consistent behaviour
Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(this)
}
}
Then use it like this:
getString(R.string.welcome).fromHtml()
You can do it from string
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="total_review"><b>Total Review: </b> </string>
</resources>
and can access it from the java code like
proDuctReviewNumber.setText(getResources().getString(R.string.total_review)+productDetailsSuccess.getProductTotalReview());
In Kotlin I have created an extension function for the Context. It takes a @StringRes and optionally you can provide parameters as well.
fun Context.fromHtmlWithParams(@StringRes stringRes: Int, parameter : String? = null) : Spanned {
val stringText = if (parameter.isNullOrEmpty()) {
this.getString(stringRes)
} else {
this.getString(stringRes, parameter)
}
return Html.fromHtml(stringText, Html.FROM_HTML_MODE_LEGACY)
}
Usage
tv_directors.text = context?.fromHtmlWithParams(R.string.directors, movie.Director)
If you want to store formatted as a string variable and reuse it to text view isn't possible
If you aren't applying formatting, you can set TextView text directly by calling setText(java.lang.CharSequence). In some cases, however, you may want to create a styled text resource that is also used as a format string. Normally, this doesn't work because the format(String, Object...) and getString(int, Object...) methods strip all the style information from the string. The work-around to this is to write the HTML tags with escaped entities, which are then recovered with fromHtml(String), after the formatting takes place.
by from docs so alternatively store the string id and everyttime bind get string from using Htlm.fromHtml().. method.
ex:
Kotlin extention
fun Context.getStringFromResource(stringId: Int): Spanned {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(java.lang.String.format(resources.getString(stringId)),
Html.FROM_HTML_MODE_COMPACT)
} else {
Html.fromHtml(java.lang.String.format(resources.getString(stringId)))
}
}
In code:
getStringFromResource(id)
I was having a text something like:
Forgot Password? Reset here.
To implement this the easy way I used the existing android:textStyle="bold"
<LinearLayout
android:id="@+id/forgotPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:linksClickable="false"
android:selectAllOnFocus="false"
android:text="Forgot password? "
android:textAlignment="center"
android:textColor="@android:color/white"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:linksClickable="false"
android:selectAllOnFocus="false"
android:text="Reset here"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textStyle="bold" />
</LinearLayout>
Maybe it helps someone
strings.xml
<string name="sentence">This price is <b>%1$s</b> USD</string>
page.java
String successMessage = getText(R.string.message,"5.21");
This price 5.21 USD
If you want to use basic HTML tags in a string resource, it is necessary to escape the tags, otherwise they are ignored. Simply, replace '<' with < and '>' with '>' e.g:
<string name="bold_statement">This is a <bold> statement</string>
Will produce: This is a bold statement. When loading the String resource, make sure to use
HtmlCompat.fromHtml(stringFromResource, HtmlCompat.FROM_HTML_MODE_COMPACT)
Imagine you want nicely formatted string like this:
I do this:
<string name="dialog_upgrade_item_fx_output_text">
"[B]Unlimited support for up to 5 audio effects per audio track[/B]\n
- Multiple high quality effects available Reverb, Delay, Distortion, Compressor, Equalizer\n
- Each comes with various presets or create your own"
</string>
fun Context.formatted(resId: Int): Spanned =
Html.fromHtml(getString(resId).replace("\n", "<br>")
.replace("[B]", "<b>").replace("[/B]", "</b>"), 0)
textView(R.id.dialog_upgrade_item_text)
.text(formatted(R.string.dialog_upgrade_item_fx_output_text))
There is also native support for the same, where we don't have to hardcode any string or index and it plays way better in internalisation of the strings
You can define the strings like below in strings.xml as that will help in the translation of the string in other languages as well
<string name="styled_hello_world"><annotation type="bold">bold text</annotation> Hello World</string>
You can apply string id in your TextView
in your UI XML.
And in the code, you can write something like below
val spannedText = textView.text as SpannedString
// get all the annotation spans from the text
val annotations = spannedText.getSpans(0, spannedText.length, android.text.Annotation::class.java)
val spannableString = SpannableString(spannedText)
annotations.forEach { annotation ->
if (annotation.key == "type") {
val styleValue = annotation.value
if (styleValue == "bold") {
spannableString.setSpan(
StyleSpan(android.graphics.Typeface.BOLD),
spannedText.getSpanStart(annotation),
spannedText.getSpanEnd(annotation),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
textView.text = spannableString
You can find more details in the blog post
精彩评论