Spannable String: Text Styling with Spans

Banner Spannable String Text Styling With Spans

Text styling is one of the important aspects when it comes to enhancing the UI of an Android application. In Android, we can change the size, color, weight, style, etc of a text and make the text more attractive and appealing.

But think of a situation, when you want different colors for different parts of a TextView. For example, if the text is "Hello Android" and you want to have the color of "Hello" as green and "Android" as red. How can you achieve this? You can make two TextViews and set the textColor to green and red respectively. But it is not a good way of doing this. So, here comes the role of Styling the texts with the help of Spans.

In this blog, we are going to learn how to use Spans for styling our text used in our application. We are going to cover the following topics:

  • What are Spans?
  • Change different colors for different words in a TextView
  • Spannable Flags
  • Change the background color of some part of a TextView
  • Multiple Spans to the same text
  • Different font size of the string in the same TextView
  • Underline a part of the text in TextView
  • Set some part of the TextView Clickable
  • Add a Bulleted list in Android

What are Spans?

Spans are markup objects that are used to style a text either at the character level(for example, changing colors of different words) or at the paragraph level(for example, making a bullet list).

In order to style a text with the help of Spans, you can use the following three classes:

  • SpannedString: This is used when there is no need to modify the text or the markup after its creation.
  • SpannableString: This is used when there is no need to modify the text but you need to modify the markup i.e. you need to add some spans to your text.
  • SpannableStringBuilder: This is used when you need to modify the text as well as the markup.

This is a quick intro about the Spans in Android. Now, let's see some of the use-cases of it. In all of our example, we are going to use the following TextView having id as tvMessage:

<TextView
    android:id="@+id/tvMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:gravity="center"
    android:textColor="@color/black"
    android:textSize="24sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:text="Hello World!" />

Change different colors for different words in a TextView

There may be situations when you want to have different colors for a different part of the same textview. So, here you can use the ForegroundColorSpan.

val spannable = SpannableString("You can start learning Android from MindOrks")
spannable.setSpan(
    ForegroundColorSpan(Color.RED),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
tvMessage.text = spannable

Here, we are changing the color of "MindOrks" to Red. The output of the above code will be:

Foreground Color Span Example

If you look at the code, then you will find that we are using the SpannableString class because we are having a fixed text. Also, we are using the setSpan method to set the foreground color of text starting from the 36th position and ending at the 44th position in the string. Also, we are passing some flags with it i.e. the Spannable.SPAN_EXCLUSIVE_INCLUSIVE.

Let's learn about these flags.

Spannable Flags

There are many flags that can be used with Spans but the most commonly used flags are:

  • SPAN_EXCLUSIVE_EXCLUSIVE
  • SPAN_EXCLUSIVE_INCLUSIVE
  • SPAN_INCLUSIVE_EXCLUSIVE
  • SPAN_INCLUSIVE_INCLUSIVE

These flags are used to tell the Spans whether or not the Span should include the text that is inserted at the start or the end position. Inclusive means add it to the Span and exclusive means remove it from the Span.

If you are using an immutable string i.e. if you are not adding other strings with your original string then all the four flags will work the same. But if you are using a mutable string, then the role of these four flags will come into play. Let's understand this with the help of an example.

Here, we are going to insert some text in our original string. So, as discussed earlier, for mutable string, we need to use the SpannableStringBuilder.

val spannableStringBuilder = SpannableStringBuilder("Android")
spannableStringBuilder.setSpan(
    ForegroundColorSpan(Color.RED),
    1, // start
    4, // end
    Spannable.SPAN_INCLUSIVE_INCLUSIVE
)
spannableStringBuilder.insert(4, "1")
spannableStringBuilder.insert(1, "1")
tvMessage.text = spannableStringBuilder

The corresponding output for all the four flags are shown as below:

Span Flag Example

Multiple Spans to the same text

You can use the setSpan method as many times as you want on a single text also. For example, if you want to change the color of a text, make it bold and italic at the same time, then you can do this by:

val spannable = SpannableString("You can start learning Android from MindOrks")
spannable.setSpan(
    ForegroundColorSpan(Color.RED),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
spannable.setSpan(
    StyleSpan(Typeface.BOLD_ITALIC),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
tvMessage.text = spannable

Here, the color of the text is Red and it is bold and italic at the same time. The output of the above code will be:

Multiple Spans Example

You can use the setSpan method as many times as you want.

Change the background color of some part of a TextView

You can change the background color of some parts of the text in the TextView by using BackgroundColorSpan.

val spannable = SpannableString("You can start learning Android from MindOrks")
spannable.setSpan(
    BackgroundColorSpan(Color.RED),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
tvMessage.text = spannable

Here, we are changing the background to Red. The output of the above code will be:

Background Color Span Example

Different font size of the string in the same TextView

You can use RelativeSizeSpan to change the size of some parts of the TextView. The change in the size of the text will be relative i.e. with respect to other text in the string.

val spannable = SpannableString("You can start learning Android from MindOrks")
spannable.setSpan(
    RelativeSizeSpan(2f),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
tvMessage.text = spannable

Here, the size of "MindOrks" is 2f than other text. The output of the above code will be:

Relative Size Span Example

Underline a part of the text in TextView

You can underline a part of the text by using the UnderlineSpan as below:

val spannable = SpannableString("You can start learning Android from MindOrks")
spannable.setSpan(
    UnderlineSpan(),
    36, // start
    44, // end
    Spannable.SPAN_EXCLUSIVE_INCLUSIVE
)
tvMessage.text = spannable

The output of the above code will be:

Underline Span Example

Set some part of the TextView Clickable

You can set some parts of the TextView clickable using the ClickableSpan. For example:

val spanText = SpannableStringBuilder("MindOrks")

val clickableMindOrks = object : ClickableSpan() {
    override fun onClick(view: View) {
        Toast.makeText(view.context, "MindOrks Clicked!", Toast.LENGTH_SHORT).show()
    }
}
spanText.setSpan(
    clickableMindOrks,
    0,
    spanText.length,
    0
)
spanText.setSpan(
    ForegroundColorSpan(Color.RED),
    0, // start
    8, // end
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
tvMessage.setText(spanText, TextView.BufferType.SPANNABLE)

Here, on clicking "MindOrks" a toast is displayed. The output of the above code will be:

Clickable Span Example

Add a Bulleted list in Android

With the help of BulletSpan, you can create a bullet list in your application to display some information in a short and simple way.

// function to covert a list into bullet list
fun convertToBulletList(stringList: List<String>): CharSequence {
    val spannableStringBuilder = SpannableStringBuilder("Learn Android from\n")
    stringList.forEachIndexed { index, text ->
        val line: CharSequence = text + if (index < stringList.size - 1) "\n" else ""
        val spannable: Spannable = SpannableString(line)
        spannable.setSpan(
            BulletSpan(15, Color.RED),
            0,
            spannable.length,
            Spanned.SPAN_INCLUSIVE_EXCLUSIVE
        )
        spannableStringBuilder.append(spannable)
    }
    return spannableStringBuilder
}
val androidResourceList = listOf("MindOrks Course", "MindOrks Blog", "MindOrks OpenSource", "MindOrks YouTube")
tvMessage.text = convertToBulletList(androidResourceList)

The output of the above code will be:

Bullet Span Example

So, in this way, we can use Spans to style the texts present in our application.

Hope you learned something new today and I am sure that you are going to use these awesome features in your app very soon.

Do share this blog with other developers to spread the knowledge.

Keep Learning!

Also, Let’s connect on Twitter, Linkedin, Github, and Facebook