开发者

Bold words in a string of strings.xml in Android

开发者 https://www.devze.com 2023-03-29 16:58 出处:网络
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.

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 &lt;

To be like this:

<string name="welcome">Welcome to &lt;b>Android&lt;/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 &lt; and '>' with '&gt;' e.g:

<string name="bold_statement">This is a &lt;bold&gt; 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:

Bold words in a string of strings.xml in Android

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号