NOTE: This post was originally written in 2010 so it may be dated. I’m resurrecting it due to relative popularity. This post has been copied between several blogging systems (some of which were home-brewed) and some formatting has been lost along the way.
Even a developer-friendly mobile platform like Android can have a developer feeling a little lost when trying to perform simple tasks when you’re unfamiliar with the platform.
One of these simple, however poorly documented, tasks is rich-style text formatting within a TextView.
SpannableString
While it’s possible to set a TextView‘s text property to a simple String and configure the TextView to have the formatting you desire you’re then limited in how granular you can control the formatting within the TextView itself. The SpannableString class allows you to easily format certain pieces (spans) of a string one way and other pieces another by applying extensions of CharacterStyle (i.e. ForegroundColorSpan) via the setSpan method.
In the end this isn’t limited to formatting. It also allows the developer to add behaviors to spans such as reacting to click events.
Example
Here’s an example onCreate method of an Activity. This assumes there’s a main.xml layout with a TextView identified by “rich_text”.
Essentially this code will set a TextView’s text to the familiar, “Lorem ipsum dolor sit amet” and perform the following formatting:
- Make “Lorem” red
- Make “ipsum” a 1.5 times bigger than what the TextView’s setting
- Make “dolor” display a toast message when touched
- Strike through “sit”
- Make “amet” twice as big as the TextView’s setting, green and a link to this site
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
richTextView = (TextView)findViewById(R.id.rich_text);
// this is the text we'll be operating on
SpannableString text = new SpannableString("Lorem ipsum dolor sit amet");
// make "Lorem" (characters 0 to 5) red
text.setSpan(new ForegroundColorSpan(Color.RED), 0, 5, 0);
// make "ipsum" (characters 6 to 11) one and a half time bigger than the textbox
text.setSpan(new RelativeSizeSpan(1.5f), 6, 11, 0);
// make "dolor" (characters 12 to 17) display a toast message when touched
final Context context = this;
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View view) {
Toast.makeText(context, "dolor", Toast.LENGTH_LONG).show();
}
};
text.setSpan(clickableSpan, 12, 17, 0);
// make "sit" (characters 18 to 21) struck through
text.setSpan(new StrikethroughSpan(), 18, 21, 0);
// make "amet" (characters 22 to 26) twice as big, green and a link to this site.
// it's important to set the color after the URLSpan or the standard
// link color will override it.
text.setSpan(new RelativeSizeSpan(2f), 22, 26, 0);
text.setSpan(new URLSpan("http://www.chrisumbel.com"), 22, 26, 0);
text.setSpan(new ForegroundColorSpan(Color.GREEN), 22, 26, 0);
// make our ClickableSpans and URLSpans work
richTextView.setMovementMethod(LinkMovementMethod.getInstance());
// shove our styled text into the TextView
richTextView.setText(text, BufferType.SPANNABLE);
}
The results of which will look something like:
Note that we set the TextView’s movement method to a LinkMovementMethod instance. Without that the ClickableSpan and URLSpans won’t perform their intended actions.
Next Steps
This covers the fundamental concepts, but there are many extensions of CharacterStyle I haven’t covered here. Check out the CharacterStyle documentation for more details.
Also note that a SpannableStringBuilder is provided for building large spannables from smaller pieces.