Plain text is so… plain.
Fortunately, Android has fairly extensive support for formatted text, before you need to break out something as heavyweight as WebView. However, some of this rich-text support has been shrouded in mystery, particularly in how you would allow users to edit formatted text.
So, let’s talk a bit about how rich text works.
You may have noticed that many methods in Android accept or return a CharSequence. The CharSequence interface is little used in traditional Java, if for no other reason than there are relatively few implementations of it outside of String. However, in Android, CharSequence becomes much more important because of a sub-interface named Spanned.
Spanned defines sequences of characters (CharSequence) that contain inline markup rules. These rules—instances of CharacterStyle—indicate whether the “spanned” portion of the characters should be rendered in an alternate font, or be turned into a hyperlink, or have other effects applied to them. Methods that take a CharSequence as a parameter, therefore, can work equally well with String objects as with objects that implement Spanned.
The base interface for rich-text CharSequence objects is Spanned. This is used for any CharSequence that has inline markup rules, and it defines methods for retrieving markup rules applied to portions of the underlying text. The primary concrete implementation of Spanned is SpannedString. SpannedString, like String, is immutable: You cannot change either the text or the formatting of a SpannedString.
There is also the Spannable sub-interface of Spanned. Spannable is used for any CharSequence with inline markup rules that can be modified, and it defines the methods for modifying the formatting. There is a corresponding SpannableString implementation.
Finally, there is a related Editable interface, which is for a CharSequence that can have its text modified in-place. SpannableStringBuilder implements both Editable and Spannable for modifying text and formatting at the same time.
One of the most important uses of Spanned objects is with TextView. TextView is capable of rendering a Spanned, complete with all of the specified formatting. So, if you have a Spanned that indicates that the third word should be rendered in italics, TextView will faithfully italicize that word.
TextView, of course, is an ancestor of many other widgets, from EditText to Button to CheckBox. Each of those, therefore, can use and render Spannable objects.
As noted above, the markup rules come in the form of instances of a base class known as CharacterStyle. Despite that name, all of the SDK-supplied subclasses of CharacterStyle end in Span (not Style), and so you will likely see references to these as “spans” as often as “styles.” That also helps minimize confusion between character styles and style resources.
There are well over a dozen supplied CharacterStyle subclasses, including:
1. ForegroundColorSpan and BackgroundColorSpan for coloring text
2. StyleSpan, TextAppearanceSpan, TypefaceSpan, UnderlineSpan and StrikethroughSpan for affecting the true “style” of text
3. AbsoluteSizeSpan, RelativeSizeSpan, SuperscriptSpan and SubscriptSpan for affecting the size (and, in some cases, vertical position) of the text
And so on.
Spanned objects do not appear by magic. There are only a few ways that you as a developer will get a Spanned complete with formatting.
The primary way most developers get a Spanned object into their application is via a string resource. String resources support inline markup in the form of HTML tags. Bold (<b>), italics (<i>) and underline (<u>) are officially supported. When you retrieve the string resource via getText(), you get back a CharSequence that represents a Spanned object with the markup rules in place.
The next most common way to get a Spanned object is to use Html.fromHtml(). This parses an HTML string and returns a Spanned object, with all recognized tags converted into corresponding spans. You might use this for text loaded from a database, retrieved from a Web service call, extracted from an RSS feed, etc. Unfortunately, the list of tags that fromHtml() understands is undocumented. Based on the source code to fromHtml(), the following seem safe:
1. <a href=”…”>
8. <div align=”…”>
10. <font size=”…” color=”…” face=”…”>
18. <img src=”…”>
The getText() method on EditText returns an Editable object, not a simple string. That’s because, in theory, EditText could be returning something with formatting applied. The call to toString() simply strips out any potential formatting as part of giving you back a String. And, of course, you are welcome to create a SpannableString via its constructor, supplying the text that you wish to display, then calling various methods on SpannableString to format it. Or you are welcome to create a SpannableStringBuilder via its constructor.
In some respects, SpannableStringBuilder works like the classic StringBuilder: You call append() to add more text. However, SpannableStringBuilder also offers delete(), insert() and replace() methods to modify portions of the existing content. It also supports the same methods that SpannableString does, via the Spannable interface, for applying formatting rules to portions of text.