Getting Started with Spannables on Android

Begin formatting text like a pro!

Fouad Olaore
Programming Geeks
10 min readAug 16, 2020

--

Text, probably the most basic element you get to work with on Android, and sometimes we have to format certain parts of our text. Formatting helps place emphasis on text, indicating that the formatted parts of text mean more when compared to plain parts. Formatting options include underline, bold, italics, strikethrough and many more. Android provides a number of options to its’ developers when it comes to formatting text. A direct approach is by using HTML markup to define sections of our text to be formatted, tags like the <u> — underline, <b> — bold and <i> — italics do just that. Android properly helps us convert the markup provided into nicely formatted text.

Using XML

<resources> 
<string name=”formatted_text”>This text is <b>bold<b> and this is <u>underlined</u>
</string>
</resources>

Or Code

val text = "This text is <b>bold<b> and this is <u>underlined</u>" myTextView.text = Html.fromHtml(text, HTML.FROM_HTML_MODE_LEGACY)

We have an awesome option for formatting, don’t we? but that’s not all there is to formatting.

Formatting is the arrangement of a material in a particular layout, shape, size and general makeup — Merriam-Webster

Formatting goes beyond boldening or underlining text, we have a pool of design possibilities we can replicate. For example, we might want to set the colour of a fraction of our text differently or its size or its background, whatever. These designs are achievable using spannables without having to worry about too much.

Our First Spannable

To get started, create a new android studio project with your preferred project name and add this to the activity_main.xml. In the code below, we have a parent LinearLayout and five textviews. Android treats spannables like basic text so we can easily set the formatted text to the textviews, hence the usage of textviews.

In the layout above, we created five TextViews to hold differently formatted text, we’d go through them one after the other, starting with the bold format. But before that, let’s take a moment to understand the general structure of how spannables are set up and how the formatting takes place.

How are spannables set up?

When it comes to using Spannables, we can create them in three ways. By using any of the SpannedString, SpannableString and the SpannableStringBuilder classes. Each of these classes has features that differentiate them, the differences are outlined below.

  1. SpannedString — This class does not allow modifications to the text set into the Spannable. No modifications to the text and no modifications to the design (the spans). In other words, it’s immutable.
  2. SpannableString — This class allows for modifications of the design/styles added to the text, but no direct modification of the text used by the Spannable.
  3. SpannableStringBuilder — This class allows for modifications to the text itself and its designs.

The key takeaway here can be summarised as such:

Use SpannedString when you want to set the text and design once without any further modifications, SpannableString when you won’t be making any changes to the text but to the design and SpannableStringBuilder when you’d be making changes to both the underlying text and the design.

Format For Spannables

Now that we have a clear view of the types of spans we can use, let’s dig deeper into their general structure. Spannables you’d use in the future generally come in this fashion:

spannableObject.setSpan(Object what, int startIndex, int endIndex, int flags)

Our spannable object provides a setSpan method we can use to apply different span styles to sections of our text. It takes in four arguments, let’s dive in!

  1. what This refers to the actual span style we would be applying, think of it as an object that instructs our spannable to apply a certain style to the text.
  2. startIndex Remember our spannables deal with text? Right. The startIndex parameter denotes the index where the text to be formatted begins. Say the text to be formatted is thyself in steady thyself, we could deduce that the startIndex for this text is 7.
  3. endIndex This does pretty much the opposite of what the startIndex does, it denotes the index of the character that ends the text to be formatted. Using our example from our startIndex explanation, our endIndex is the index of the letter f in thyself, so that would make it 13.
  4. flags This indicates how the text provided to the spannables should be treated, we have various values that can be assigned to this parameter position, examples are SPAN_EXCLUSIVE_EXCLUSIVE, SPAN_EXCLUSIVE_INCLUSIVE, SPAN_INCLUSIVE_INCLUSIVE and many more. A detailed explanation is provided below.

Spannable Flags

As explained above, spannable flags indicate how the Spanning process should treat the text to be spanned. Some of the flags we can use are explained below.

  1. SPAN_INCLUSIVE_INCLUSIVE: This allows new text to be added to both the starting and end points of the text.
  2. SPAN_INCLUSIVE_EXCLUSIVE: This allows new text to be added to the starting point, but not to the end.
  3. SPAN_EXCLUSIVE_INCLUSIVE: This does not allow text to be added to the starting point, but the end.
  4. SPAN_EXCLUSIVE_EXCLUSIVE: This does not allow text to be added to the start and end points of the text.

You can read about other span flags here, since we have covered the general structure of applying spans, and dug deep into it’s required parameters, this seems like a good time to write our first span.

The Bold Span

Let’s start by retrieving a reference to a TextView in our layout, and then setting up a function to apply the spanning. We do that by writing:

This serves as a good starting point for us, and we can now get right to formatting.

We start by creating a string variable to hold the whole text to be set in the TextView, since we would not be formatting all of the text, we also need to get the exact text to be formatted, in this case a variable with the string “bold”. We’ve got that on check, now we have to construct the actual SpannableString object, we do this by invoking the SpannableString constructor and passing the whole text as an argument. This tells the SpannableString object that this is text we would be applying formatting options to.

Looking back at our setSpan method, we need to pass in the start and end indexes of the text to be formatted, we want to format the text “bold”, so we have to get the startIndex of that text, we do that, and assign it’s value to the startIndex variable, we do something similar to the endIndex, this would be startIndex added to the amount of characters of the text to be formatted — 4. After this, we SET THE SPAN!

To apply style spans to text, we use the StyleSpan constructor. We want to apply the bold effect right?, so we employ the Typeface.BOLD effect. By doing this, we apply the bold effect to the spanned text. Other formatting options that can be added are Typeface.ITALICS and Typeface.BOLD_ITALICS. We pass in the start and end index together with the appropriate flag, and we set the text in the TextView to the created spannable. We then come up with this!

span effects for bold text

The Foreground Span

We follow the same approach as before in getting a reference to the TextView and creating a method to setup the foreground span effect.

Let’s apply the span, yeah!

In this example, we would be applying the foreground effect to two parts of our text. We start again by getting the whole text and saving it in a variable, with this variable, we in turn create our SpannableString object. The first part of the text to be formatted has the content “part of this text”. We get the startIndex and the amount of characters of this text. Back in our setSpan method, we use the ForegroundColorSpan object to apply a color, we pass in Color.RED, we then configure the start and end index. and the first red color effect gets applied. Check it out before we move to the next.

span effects for foreground text — 1

Looks good right?

For this next example, we follow a similar pattern, all we need to do is to re-initialize the values of startIndex and amountOfCharacters so we deduce a new start and end index for the text this time. With this we apply text formatting to two different sections of our text.

startIndex = foregroundSpannableText.indexOf("red")  amountOfCharacters = 3 // length of "red"   foregroundSpannableText.setSpan(        ForegroundColorSpan(Color.RED), startIndex, startIndex + amountOfCharacters, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
foregroundText.text = foregroundSpannableText
span effects for foreground effects — 2

Foreground and Background Spans

We’ve covered foreground color spans, let’s look into applying background effect, but with a little twist. We’d be applying both foreground and background spans on the same piece of text, simulating a highlight. Let’s give it a try! We start by getting a reference to the textview and setting up it’s function.

Now that’s all set up, let’s apply the actual spans!

The process of applying a background color span to our text is similar to the foreground color and we come up with this effect.

span effects for background and foreground text

Sizing Spans

We can also format the size of text different from the rest using size spans. These allow us to change the size of part of our text by applying certain metric values. Generally, when formatting the size of text, there are two approaches — AbsoluteSizeSpan and RelativeSizeSpan.

  1. AbsoluteSizeSpan — This size span gives an absolute size to the area to be formatted, it’s value is direct and not in relation to other text. For example, if our main text has a size of 20dp and we apply a size of 10dp to the text to be formatted, the formatted text appears smaller.
  2. RelativeSizeSpan — This is different from the AbsoluteSizeSpan because it sizes the formatted text based on the original size of the main text. It’s more like a scaling approach, it takes in a value to scale the formatted text by depending on the main text. If provided with a scale value of 1.5f, the formatted text’s size if 1.5x the main text.

Let’s try both of them out.

Absolute Sizing

As explained above, using absolute sizing gives a size independent of the parent’s size. Let’s give it a shot! We start by retrieving a reference to the sizing textview as usual, and provide a definition for the function meant to do the actual formatting.

And now, we format!

At this point, we should be familiar with the general approach to applying spans, and for this use-case, we pass in 20 as the absolute font size for the text “smaller”, and this effect is applied.

span effects for absolute text sizing

Relative Sizing

Relative sizing entails calculating the font size of the formatted text in relation to its’ parent. It’s safe to say that the original font size of the parent text is scaled by the value provided. Let’s dive in!

We start by getting a reference to the sizingBiggerText textview.

Off to formatting!

In this example, we use the RelativeSizeSpan constructor, we pass in a float value (2f). This instructs the spanning process to size the formatted text to be double the size of the parent text. The outcome of this process can be found below….

span effects for relative text sizing

Interlude

We’ve applied lots of span effects and it’s thrilling to be able to come up with such minimalistic designs with little or no effort. I stated at the start of this article that we have a handful of methods of applying span effects. We’ve only gone through the use of SpannableString, next we’re going check out the SpannableStringBuilder and how it helps us apply spans to text while joining chunks of text as we go on.

SpannableStringBuilder

With the SpannableStringBuilder, we do not have to set all the text at once, we can set text when we want and format later. We can also append chunks of text later on in our program, and apply formatting options to them. In this example, we would be using the bold, underline and the strikethrough effect on different sections in the same parent text. We start by getting the reference to the text and set up the method for formatting.

then we format!

Whoa!, this might seem ambiguous at first, but it is quite easy to wrap your head around. As usual, we deduce the start index and amount of characters for the string “bold”, after applying the bold effect, we append new text to the end of the spannable object. We calculate the start index and the amount of characters of the text to be formatted again, we apply the strikethrough span using the StrikethroughSpan constructor. We add the text to be underlined to the end of the spannable object. We set the span by applying the UnderlineSpan constructor and finally we set the spannable text to the text present in the texview. The final result is as such:

span effects for strikethrough, bold and underline text

What’s Next?

We’ve learnt how to apply spans to text and make our designs and text stand out. You can try applying other kinds of spans to our text to make it more attractive. If you have any question(s), kindly drop a comment below this article or reach out to me on Twitter, I’d be willing to provide help or attention in any way possible.

Thanks for reading!, and happy formatting!.

--

--

Fouad Olaore
Programming Geeks

Software Engineer. Speeding up manufacturing with code at Protolabs.