HTML in string resource?
Asked Answered
N

6

137

I know I can put escaped HTML tags in string resources. However, looking at the source code for the Contacts application I can see that they have a way of not having to encode the HTML. Quote from the Contacts application strings.xml:

<string name="contactsSyncPlug"><font fgcolor="#ffffffff">Sync your Google contacts!</font> 
\nAfter syncing to your phone, your contacts will be available to you wherever you go.</string>

Unfortunately, when I try something similar (like Hello, <b>World</b>!), getString() returns the string without the tags (I can see that in logcat). Why is that? How can I get the original string, with tags and everything? How is the Contacts application doing it?

Noleta answered 19/4, 2010 at 12:26 Comment(1)
Proper solution : developer.android.com/guide/topics/resources/…Cerelia
N
104

It seems getString() does just that -- gets a string. To use this, you have to use getText() (and no more Html.fromHtml()), i.e.:

mTextView.setText(getText(R.string.my_styled_text));

However, it seems the android:text property does just the same thing, and the following is equivalent:

<TextView android:text="@string/my_styled_text" />

And in strings.xml:

<string name="my_styled_text">Hello, <b>World</b>!</string>
Noleta answered 19/4, 2010 at 13:12 Comment(13)
note getString() returns CharSequence, not a usual String. so if html tags are used, then CharSequence also includes info about them, and thus mTextView.setText(getText(R.string.my_styled_text)) works as expected.Spokane
Please note that only supported tags are <b>, <i>, <u> : developer.android.com/guide/topics/resources/…Davon
and instead of <br/> you can use /nGermanism
@Germanism surely you mean \n?Noleta
This doesn't work for anything besides the three HTML tags listed above, so this doesn't answer the question really at allBeware
@Snicolas: it does support more than the 3 tags mentioned in the documentation: it supports <b>, <i>, <u>, <big>, <small>, <sup>, <sub>, <strike>, <li>, <marquee>, <a>, <font> and <annotation> (see github.com/android/platform_frameworks_base/blob/…)Damiandamiani
This works great, but just something that set me back for a while - if using Eclipse, these tags may not display properly in the visual layout editor. (They will display when running on a device or emulator.)Related
Unfortunatly using this method, variables in string are not allowedLiquidambar
<font> is supported at api23, but api10 is not.Conchitaconchobar
Works for me. Thanks!Ileum
Check the link for detailed explanation about the above method.#45648428.Homomorphism
Seems the docs have been updated since last activity here, but the documented tags still don't seem to align with the StringBlock.java code. Can anyone clarify?Warrick
this answer is gold should really be the accepted onePiled
E
226

You can also surround your html in a CDATA block as well and getString() will return your actual HTML. Like such:

<string name="foo"><![CDATA[Foo Bar <a href="foo?id=%s">baz</a> is cool]]></string>

Now when you perform a getString(R.string.foo) the string will be HTML. If you need to render the HTML (with the link as shown) via a clickable TextView you'd need to perform a Html.fromHtml(...) call to get the spannable text.

Expunction answered 3/10, 2011 at 22:2 Comment(8)
No, you should definitely see Felix's answer. CDATA is not necessary.Maines
@MarcoW. Felix's answer is true but using CDATA helps us to not to worry about html tags. This answer should be correct answer.Broadcloth
If you have links in the string, don't forget to add textView.setMovementMethod(LinkMovementMethod.getInstance());Leonleona
I had to use \" for style property, though. Example <a style=\"...\">link</a>Apterygial
CDATA gives you a lot more flexibility when styling strings with HTML tags. I would agree that is the way to go 100%!Scrimpy
TextView tv = (TextView) findViewById(R.id.textHolder); tv.setText(Html.fromHtml(getString(R.string.foo))); tv.setMovementMethod(LinkMovementMethod.getInstance());Ubangishari
Also, getText() doesn't accept format arguments. If you have something other than a static string you must use getString() + Html.Medick
Use this ink : developer.android.com/guide/topics/resources/…Cerelia
N
104

It seems getString() does just that -- gets a string. To use this, you have to use getText() (and no more Html.fromHtml()), i.e.:

mTextView.setText(getText(R.string.my_styled_text));

However, it seems the android:text property does just the same thing, and the following is equivalent:

<TextView android:text="@string/my_styled_text" />

And in strings.xml:

<string name="my_styled_text">Hello, <b>World</b>!</string>
Noleta answered 19/4, 2010 at 13:12 Comment(13)
note getString() returns CharSequence, not a usual String. so if html tags are used, then CharSequence also includes info about them, and thus mTextView.setText(getText(R.string.my_styled_text)) works as expected.Spokane
Please note that only supported tags are <b>, <i>, <u> : developer.android.com/guide/topics/resources/…Davon
and instead of <br/> you can use /nGermanism
@Germanism surely you mean \n?Noleta
This doesn't work for anything besides the three HTML tags listed above, so this doesn't answer the question really at allBeware
@Snicolas: it does support more than the 3 tags mentioned in the documentation: it supports <b>, <i>, <u>, <big>, <small>, <sup>, <sub>, <strike>, <li>, <marquee>, <a>, <font> and <annotation> (see github.com/android/platform_frameworks_base/blob/…)Damiandamiani
This works great, but just something that set me back for a while - if using Eclipse, these tags may not display properly in the visual layout editor. (They will display when running on a device or emulator.)Related
Unfortunatly using this method, variables in string are not allowedLiquidambar
<font> is supported at api23, but api10 is not.Conchitaconchobar
Works for me. Thanks!Ileum
Check the link for detailed explanation about the above method.#45648428.Homomorphism
Seems the docs have been updated since last activity here, but the documented tags still don't seem to align with the StringBlock.java code. Can anyone clarify?Warrick
this answer is gold should really be the accepted onePiled
N
62

The best solution is to use resources in a way:

<string name="htmlsource"><![CDATA[<p>Adults are spotted gold and black on the crown, back and wings. Their face and neck are black with a white border; they have a black breast and a dark rump. The legs are black.</p><p>It is similar to two other golden plovers, Eurasian and Pacific. <h1>The American Golden Plover</h1> is smaller, slimmer and relatively longer-legged than Eurasian Golden Plover (<i>Pluvialis apricaria</i>) which also has white axillary (armpit) feathers. It is more similar to Pacific Golden Plover (<i>Pluvialis fulva</i>) with which it was once <b>considered</b> conspecific under the name \"Lesser Golden Plover\". The Pacific Golden Plover is slimmer than the American species, has a shorter primary projection, and longer legs, and is usually yellower on the back.</p><p>These birds forage for food on tundra, fields, beaches and tidal flats, usually by sight. They eat insects and crustaceans, also berries.</p>]]></string>

and than display it with:

Spanned sp = Html.fromHtml( getString(R.string.htmlsource));
tv.setText(sp);

Try to use that resource without <![CDATA[ ]]> and with tv.setText(getText(R.string.htmlsource)); and you will see the difference.

Nuptials answered 9/11, 2011 at 13:1 Comment(3)
Thank you for this answer this really helped meCostly
Even with a very large and complex HTML file?Arabeila
Does this support <font> tag?Hanselka
L
4

I know this is an old question but it seems the most efficient answer has not been proposed yet.

Just use HTML-escaped characters so it won't get processed by getString but it will be processed by HtmlCompat.fromHtml (or the older Html.fromHtml).

This also supports more tags like HTML links etc., not only formatting like getString method.

For example something like this should work:

<string name="html_message">Hello &lt;b>World&lt;/b>.</string>

val text = getString(R.string.html_message)
val result = HtmlCompact.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY)

In your case you replace < with &lt; like this:

<string name="contactsSyncPlug">&lt;font fgcolor="#ffffffff">Sync your Google contacts!&lt;/font> \nAfter syncing to your phone, your contacts will be available to you wherever you go.</string>
Leg answered 5/3, 2020 at 1:46 Comment(1)
This has the benefit of working without hassles with string parameters.Tyrontyrone
C
0

it works for me without CDATA block.

<string name="menu_item_purchase" translatable="false"><font color="red">P</font><font color="orange">r</font><font color="yellow">e</font><font color="green">m</font><font color="white">i</font><font color="blue">u</font><font color="purple">m</font></string>`enter code here`

I use it in layout.

<item
    android:id="@+id/nav_premium"
    android:icon="@drawable/coins"
    android:title="@string/menu_item_purchase"
    />
Corvus answered 3/10, 2017 at 9:53 Comment(0)
N
-2

Idea: put the HTML in JSON-formatted files and store them in /res/raw. (JSON is less picky)

Store the data records like this in an array object:

[
    {
        "Field1": "String data",
        "Field2": 12345,
        "Field3": "more Strings",
        "Field4": true
    },
    {
        "Field1": "String data",
        "Field2": 12345,
        "Field3": "more Strings",
        "Field4": true
    },
    {
        "Field1": "String data",
        "Field2": 12345,
        "Field3": "more Strings",
        "Field4": true
    }
]

To read the data in your app :

private ArrayList<Data> getData(String filename) {
    ArrayList<Data> dataArray = new ArrayList<Data>();

    try {
        int id = getResources().getIdentifier(filename, "raw", getPackageName());
        InputStream input = getResources().openRawResource(id);
        int size = input.available();
        byte[] buffer = new byte[size];
        input.read(buffer);
        String text = new String(buffer);

        Gson gson = new Gson();
        Type dataType = new TypeToken<List<Map<String, Object>>>() {}.getType();
        List<Map<String, Object>> natural = gson.fromJson(text, dataType);

        // now cycle through each object and gather the data from each field
        for(Map<String, Object> json : natural) {
            final Data ad = new Data(json.get("Field1"), json.get("Field2"),  json.get("Field3"), json.get("Field4"));
            dataArray.add(ad);
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

    return dataArray;
}

Finally, the Data class is just a container of public variables for easy access...

public class Data {

    public String string;
    public Integer number;
    public String somestring;
    public Integer site;
    public boolean logical;


    public Data(String string, Integer number, String somestring, boolean logical)
    {
        this.string = string;
        this.number = number;
        this.somestring = somestring;
        this.logical = logical;
    }
}
Nebula answered 22/1, 2014 at 23:50 Comment(1)
It seems a bit over-engineered, why not saving it in html instead of json?Cordero

© 2022 - 2024 — McMap. All rights reserved.