Sitemap

Simply Span | Android Development

6 min readApr 5, 2023

--

Press enter or click to view image in full size
A graphic containing the word “SPANS”, where the “ANS” substring is colored in yellow.

While the style attribute is useful for applying a set of predefined styles to TextView, Spans provide much more flexibility and control over text styling in Android.

What are Spans?

As the documentation clearly states, spans are powerful markup objects that you can use to style text at a character or paragraph level.

But how?

By using any of these three classes: SpannedString, SpannableString, and SpannableStringBuilder.

Android SDK provides these three classes because we can’t use spans on normal strings. We need to convert normal strings into strings on which we can apply spans, and that is done by these classes.

But why there are three?

Obviously there might be differences, right? The main difference lies in the mutability of the text and the span after object creation. It is absolutely alright if you don’t understand what that means right now. Just keep reading!

Note: After object creation, in this context, means after creating an object of any of the above three classes.

SpannableStringBuilder

It is one of the three classes that convert normal strings into spannable strings. It differs from other two because it allows applying one or more spans [styles] and also allows updating the text after object creation.

Most of things are hard to explain solely by words. For that reason, we will use examples to understand it better in the following text.

Note: In this article, the word “spannable string” and SpannableString refer to two different things. The first refers to strings on which we can apply spans, while the second refers to a class.

To create a SpannableStringBuilder object, simply use it’s constructor which takes a CharSequence as an argument.

SpannableStringBuilder(CharSequence source)

And then pass a string [Hello World] to it:

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableStringBuilder(text)

Now that we have successfully created a SpannableStringBuilder object, or we can say successfully converted a normal string into a string on which we can apply spans, it is time to apply span[s].

setSpan()

To apply spans, Android SDK provides a method, setSpan(), which has four parameters:

setSpan(Object _what_, int _start_, int _end_, int _flags_)

The first parameter what refers to the span to apply to the text, while the start and end parameters indicate the portion of the text to which to apply the span and we usually pass indices in these two parameters. The fourth or the last parameter, flags, decides whether to expand the span to include the text inserted at the span boundaries after object creation or not.

Note: A span boundary is the starting and the ending point of the portion of text where the span is applied. It is usually referred to by indices, where the start parameter is the starting point, and the end parameter is the ending point.

Let’s see how it works using an example:

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableStringBuilder(text)

spannableString.setSpan(
ForegroundColorSpan(color.RED),
6,
10,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)

In the above example, we have applied the ForegroundColorSpan, which is a type of span that changes the color of the text to which the span is attached. In this case, the color is red. Moving forward, we passed 6 and 10 respectively to the start and end parameters and then Spannable.SPAN_INCLUSIVE_INCLUSIVE to the flags parameter.

The above span will make the text “Hello World” look like this:

Press enter or click to view image in full size
A graphic containing the sentence “Hello World”, where the “Worl” substring is colored in red.

As you can see, the substring “Worl” is colored in red. I bet that many of you guessed that the word “World ” will be colored in red instead. The catch here is that the setSpan() method will apply the span to the text starting from start index until the end index, but excluding the end index.

Get The Android Blueprint’s stories in your inbox

Join Medium for free to get updates from this writer.

Now let’s talk about the argument Spannable.SPAN_INCLUSIVE_INCLUSIVE, but before that let’s insert a word at index 6 of variable spannableString, which is also a span boundary in this example.

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableStringBuilder(text)

spannableString.setSpan(
ForegroundColorSpan(color.RED),
6,
10,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)

spannableString.insert(6, "Super ")

Note: The insert() method inserts its argument string at the index of the spannable string equivalent to its argument index.

What do you see? Do you see the word “Super”, which we previously inserted at index 6, also colored in red? Like in the following picture?

Press enter or click to view image in full size
A graphic containing the sentence “Hello Super World”, where the “Super Worl” substring is colored in red.

If the answer is yes, then it’s due to the flag Spannable.SPAN_INCLUSIVE_INCLUSIVE.

Recall: The fourth or the last parameter flags of the setSpan() method decides whether to expand the span to include the text which was inserted at the span boundaries after object creation or not.

The flag Spannable.SPAN_INCLUSIVE_INCLUSIVE expands the span to include the text inserted at the starting or ending point or both of a span boundary. And in our example, the starting point is index 6 and the ending point is index 10.

Like the flag Spannable.SPAN_INCLUSIVE_INCLUSIVE, there are several other flags that you can dig into. For more info, follow the documentation.

Note: As of now, we have created a SpannableStringBuilder object, applied a ForegroundColorSpan on it, and updated the text after object creation by inserting a word at a specific index [6]. This proves that SpannableStringBuilder allows us to apply one or more spans [styles] and also allows us to change the text after object creation.

SpannableString

Now that we understood SpannableStringBuilder, this will be an easy read. This class allows us to apply one or more spans [styles] but restricts us from updating the text after object creation, unlike SpannableStringBuilder.

Let’s see what I mean using an example.

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableString(text)

spannableString.setSpan(
ForegroundColorSpan(color.RED),
6,
10,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)

spannableString.insert(6, "Super ")

If you simply copy and paste the above code in Android Studio or in any IDE, you will probably notice that the IDE shows an error on the insert() method, but not on setSpan(). This is because, as I mentioned earlier, this class allows you to apply one or more spans [styles], but doesn’t allow you to update the text after object creation.

SpannableString and SpannableStringBuilder are quite similar, except that SpannableString doesn’t allow you to change the text after object creation. To make the above code work, simply remove the line that has the insert() method.

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableString(text)

spannableString.setSpan(
ForegroundColorSpan(color.RED),
6,
10,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)

SpannedString

Now we come to the last class among the threes that can convert normal strings into spannable strings, but it does not actually apply here. That’s because this class doesn’t allow spans to be applied on it, nor does it allow the text to be updated after object creation. So, if we cannot apply spans, then how are we suppose to use it?

Confused? Don’t worry, there is simple trick to get around it. It’s worth noting that the SpannableString and SpannableStringBuilder class implements CharSequence, and the SpannedString constructor takes a CharSequence as an argument.

SpannedString(CharSequence source)

The trick here is that we simply pass a SpannableString or SpannableStringBuilder object as an argument to it.

//String in Kotlin implements CharSequence
val text = "Hello World"
val spannableString = SpannableString(text)

spannableString.setSpan(
ForegroundColorSpan(color.RED),
6,
10,
Spannable.SPAN_INCLUSIVE_INCLUSIVE
)

val spannedString = SpannedString(spannableString)

The Difference

  • SpannableStringBuilder allows the application of one or more spans [styles] and also allows updating the text after object creation.
  • SpannableString allows the application of one or more spans [styles], but restricts updating the text after object creation.
  • SpannedString doesn’t allow the application of spans [styles] or updating the text after object creation. For this reason, we either pass a SpannableStringBuilder object or a SpannableString as an argument to it.

Conclusion

In this writing, we have just explored the basics of spans. From this point onward, it is your responsibility to explore more on your own. While you are on your exploration, it’s crucial to understand that knowledge is boundless and time needed to acquire it completely is infinite. So, it’s wise to take your time and enjoy the exploration.

--

--

The Android Blueprint
The Android Blueprint
0 followers

Breaking down Android development with clarity. A developer’s notebook on Kotlin & Jetpack Compose — made simple, one note at a time.