Android – Set TextView text from html-formatted string resource in XML

androidformattinghtmltextview

I have some fixed strings inside my strings.xml, something like:

<resources>
    <string name="somestring">
        <B>Title</B><BR/>
        Content
    </string>
</resources>

and in my layout I've got a TextView which I'd like to fill with the html-formatted string.

<TextView android:id="@+id/formattedtext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/htmlstring"/>

if I do this, the content of formattedtext is just the content of somestring stripped of any html tags and thus unformatted.

I know that it is possible to set the formatted text programmatically with

.setText(Html.fromHtml(somestring));

because I use this in other parts of my program where it is working as expected.

To call this function I need an Activity, but at the moment my layout is just a simple more or less static view in plain XML and I'd prefer to leave it that way, to save me from the overhead of creating an Activity just to set some text.

Am I overlooking something obvious? Is it not possible at all? Any help or workarounds welcome!

Edit: Just tried some things and it seems that HTML formatting in xml has some restraints:

  • tags must be written lowercase

  • some tags which are mentioned here do not work, e.g. <br/> (it's possible to use \n instead)

Best Answer

Just in case anybody finds this, there's a nicer alternative that's not documented (I tripped over it after searching for hours, and finally found it in the bug list for the Android SDK itself). You CAN include raw HTML in strings.xml, as long as you wrap it in

<![CDATA[ ...raw html... ]]>

Edge Cases:

  • Characters like apostrophe ('), double-quote ("), and ampersand (&) only need to be escaped if you want them to appear in the rendered text AS themselves, but they COULD be plausibly interpreted as HTML.
    • ' and " can be represented as\' and \", or &apos; and &quot;.
    • < and > always need to be escaped as &lt; and &gt; if you literally want them to render as '<' and '>' in the text.
    • Ampersand (&) is a little more complicated.
      • Ampersand followed by whitespace renders as ampersand.
      • Ampersand followed by one or more characters that don't form a valid HTML entity code render as Ampersand followed by those characters. So... &qqq; renders as &qqq;, but &lt;1 renders as <1.

Example:

<string name="nice_html">
<![CDATA[
<p>This is a html-formatted \"string\" with <b>bold</b> and <i>italic</i> text</p>
<p>This is another paragraph from the same \'string\'.</p>
<p>To be clear, 0 &lt; 1, & 10 &gt; 1<p>
]]>
</string>

Then, in your code:

TextView foo = (TextView)findViewById(R.id.foo);
foo.setText(Html.fromHtml(getString(R.string.nice_html), FROM_HTML_MODE_LEGACY));

IMHO, this is several orders of magnitude nicer to work with :-)


August 2021 update: My original answer used Html.fromHtml(String), which was deprecated in API 24. The alternative fromHtml(String,int) form is suggested as its replacement.

FROM_HTML_MODE_LEGACY is likely to work... but one of the other flags might be a better choice for what you want to do.

On a final note, if you'd prefer to render Android Spanned text suitable for use in a TextView using Markdown syntax instead of HTML, there are now multiple thirdparty libraries to make it easy including https://noties.io/Markwon.