Written by Damian Petla
Android Developer
Published June 14, 2016

Demystify the use of HTML in TextView

As a developer you probably used or tried to use HTML tags in your TextView components to create rich text. You probably found some examples on StackOverflow, replaced the text and Voilà! Job done. If you wish to learn how this works under the hood just keep reading.

HTML class

All that interests us is inside the class android.text.Html. If you have enough patience you can go through it yourself, it’s just around 850 lines of code.

What you basically do is a call of Html.fromHtml(String source) static method passing your text wrapped with HTML tags. In return, you get an object that can be passed as a parameter in TextView.setText() method. For example:

Spanned parsedText = Html.fromHtml("<font color='#444444' face='sans-serif-medium'>Some colored</font> text");
textView.setText(parsedText);

What is going on under the hood of Html.fromHtml(String source) is:

  1. String with HTML tags is parsed into java object using SAX parser
  2. Java objects are converted into spans

That’s it. Now you may ask, what are spans? It’s a name of a powerful feature for making rich text views on Android. It’s a big mystery for me why Google is not providing any comprehensive documentation. Although, I was already writing about that here. Most of the time, as a point of reference, I use this post from Flavien Laurent.

HTML To Spanned Converter

Above I described a general overview. To get more details we have to focus on a class HtmlToSpannedConverter. This is the implementation of ContentHandler for mentioned SAX parser. We are mostly interested in 2 inherited methods:

1. startElement()
This is called for each opening tag and location of the span that is marked. For some tags e.g. font some extra properties are stored to read later.

Default start handling:

private static void start(SpannableStringBuilder text, Object mark) {
    int len = text.length();
    text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
}

Font start handling:

private static void startFont(SpannableStringBuilder text,
                                  Attributes attributes) {
    String color = attributes.getValue("", "color");
    String face = attributes.getValue("", "face");

    int len = text.length();
    text.setSpan(new Font(color, face), len, len, Spannable.SPAN_MARK_MARK);
}

2. endElement()
This is called for each closing tag. Function search for starting span, keep starting location, remove start span and then apply proper span for a tag.

Default end handling:

private static void end(SpannableStringBuilder text, Class kind,
                            Object repl) {
    int len = text.length();
    Object obj = getLast(text, kind);
    int where = text.getSpanStart(obj);

    text.removeSpan(obj);

    if (where != len) {
        text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}

Supported tags

It is very easy to list all supported HTML tags just by looking at handleEndTag method. If you expect some properties being read from a specific tag, check which method is called for it inside handleEndTag, e.g. endFont is called for font tag.
There we go:

  • br – no need to explain 🙂
  • p, div – apply line space
  • strong, b – apply BOLD style span
  • em, cite, dfn, i – apply ITALIC style span
  • big – apply 1.25 size factor
  • small – apply 0.8 size factor
  • blockquote
  • tt – apply monospace typeface
  • a
  • u – apply underline span
  • sup – apply superscript span
  • sub – apply subscript span
  • h1 to h6

Image handler

Now it’s a time to confess to a little lie 🙂 There is one special tag that is handled only in startElement method. It’s img!

To make that tag work we have to provide ImageGetter when calling Html.fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler).
It is a very simple interface with one method to implement:

Drawable getDrawable(String source) 

Once img tag is found, ImageSpan span is applied with drawable retrieved thanks to our ImageGetter. If the image getter or the drawable are not found, the Android will use a built-in drawable for unknown images.

Tag handler

Except those built-in tag handlers, we can easily add our own tag handling. As you saw above there is Html.fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler) where we can provide our TagHandler implementation.

Please note that both imageGetter and tagHandler are optional, you can always use null for one of them.

The TagHandler interface is very simple. There is just one method to implement:

public void handleTag(boolean opening, String tag,
                                 Editable output, XMLReader xmlReader);

You should know that output parameter is actually SpannableStringBuilder inside the implementation. So looking at other tags handling should give you easy start with implementing your own handler.

The end

As you saw, using HTML in TextView is very simple under the hood, there is no magic.

Written by Damian Petla
Android Developer
Published June 14, 2016