How to format and style (Bold, TextSize) string resource in Android

4.8k Views Asked by At

enter image description here

Above is the image of what I want to achieve using String.xml

There are three things

  1. '76' & '20' will be replaced dynamically using String.format
  2. '20' should be bold
  3. '20' should be bigger in size

I have tried all the solutions using Html.fromHtml class.

Following are the solutions which I have tried. I am able to make '20' bold but couldn't make the '20' bigger in size.

Following are the differet variations of String.xml which I have tried

<string name="points_data">Use %1$d points= &lt;font size="30">₹ %2$d&lt;/font> in payment</string>

<string name="points_data">Use %1$d points= <font size="14"><b>₹ %2$d</b></font> in payment</string>

<string name="points_data">Use %1$d points= &lt;font size="14">&lt;b>₹ %2$d&lt;/b>&lt;/font> in payment</string>

<string name="points_data"><![CDATA[Use %1$d points= <font size="60"><b>₹ %2$d</b></font> in payment]]></string>

<string name="points_data">Use %1$d points= &lt;b>&lt;span style="fontSize='50'">₹ %2$d&lt;/span>&lt;/b> in payment</string>

Following is the method I use for parsing above string

val formattedText = String.format(getString(R.string.points_data), 76, 20)

textViewPoints.text = HtmlCompat.fromHtml(formattedText, HtmlCompat.FROM_HTML_MODE_LEGACY)

I have came across following links while googling for solution but none of them is working for my case.

  1. https://developer.android.com/guide/topics/resources/string-resource
  2. Set TextView style (bold or italic)
  3. Html.fromHtml deprecated in Android N

I have tried all the possible solutions which I could think of but none of them is working. I don't know what I am missing to implement. If anyone knows how to achieve this scenarion or knows about a way to achieve this please provide some guidance regarding that.

2

There are 2 best solutions below

3
On BEST ANSWER

You don't need any html formatting, so you only need plain text in string resources, like this:

<string name="points_data">Use %1$d points= ₹%2$d in payment</string> 

You can use a SpannableString, to format the 2nd parameter of your string resource.
Both "%1$d" and "%2$d" will be just placeholders, so don't use String.format() in this case:

val param1 = 20.toString()
val param2 = 70.toString()

var str = getString(R.string.points_data).replace("%1\$d", param1)
val index = str.indexOf("%2\$d")
val len = param2.length
str = str.replace("%2\$d", param2)

val sp = SpannableString(str)
sp.setSpan(StyleSpan(Typeface.BOLD), index, index + len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
sp.setSpan(RelativeSizeSpan(1.5f), index, index + len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Now if you want to set the text of a TextView:

tv.text = sp

The size of the text can be altered by changing 1.5f, which is relative to the original size.

1
On

You can also use SpannableStringBuilder to achieve your required output

SAMPLE CODE

public class MainActivity extends AppCompatActivity {


    TextView tvTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvTextView = findViewById(R.id.tvTextView);
        setSpan("76", "20");
    }

    public void setSpan(String priceOne, String priceTwo) {

        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Use ");
        spannableStringBuilder.append(priceOne);

        SpannableString text = new SpannableString("$" + priceTwo);
        text.setSpan(new RelativeSizeSpan(1.5f), 0, text.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        spannableStringBuilder.append(" Points =");
        spannableStringBuilder.append(text);
        spannableStringBuilder.append(" in Payment");

        tvTextView.setText(spannableStringBuilder);
    }

}

OUTPUT

enter image description here

UPDATE

as per your below comment

Yes. I could use this but my application also supports Hindi language. And for these localization scenario, I think, using SpannableStringBuilder would be some what difficult to manage

Than add your strings in res/values/string.xml like this

<resources>
    <string name="app_name"> Demo App</string>
    <string name="search">Search</string>
    <string name="str_use">Use</string>
    <string name="str_points">Points =</string>
    <string name="str_payment">in Payment</string>


</resources>

Than use like this

public class MainActivity extends AppCompatActivity {

    TextView tvTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvTextView = findViewById(R.id.tvTextView);
        setSpan("76", "20");
    }

    public void setSpan(String priceOne, String priceTwo) {

        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(getString(R.string.str_use));
        spannableStringBuilder.append(priceOne);

        SpannableString text = new SpannableString("$" + priceTwo);
        text.setSpan(new RelativeSizeSpan(1.5f), 0, text.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        spannableStringBuilder.append(getString(R.string.str_points));
        spannableStringBuilder.append(text);
        spannableStringBuilder.append(getString(R.string.str_payment));

        tvTextView.setText(spannableStringBuilder);
    }

}