Skip to content

Android Textview Spannable Cheat Sheet

Note that this cheat sheet will explain everything using text.setSpan. The code that around this should resemble something like this.

val text = SpannableString("Hello World")
text.setSpan(...)
textview.setText(text, TextView.BufferType.SPANNABLE)

Bold

text.setSpan(
        StyleSpan(android.graphics.Typeface.BOLD),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Italic

text.setSpan(
        StyleSpan(android.graphics.Typeface.ITALIC),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Bold Italic

text.setSpan(
        StyleSpan(android.graphics.Typeface.BOLD_ITALIC),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Hyperlink

text.setSpan(
        URLSpan(url),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Text Colour (Forground Colour)

text.setSpan(
        ForegroundColorSpan(Color.BLUE),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Background Colour

text.setSpan(
        BackgroundColorSpan(Color.BLUE),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

Superscript

text.setSpan(
        SuperscriptSpan(),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Subscript

text.setSpan(
        SubscriptSpan(),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Bulleted List

text.setSpan(
        BulletSpan(gapWidth, bulletColour),
        0,
        text.length,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

BulletSpan extends LeadingMarginSpan so the first character of the span must be at the start of a paragraph and the span will cover the whole of each start of paragraphs within its range.

Ordered List

var itemOrdinal = 1
var currentItemIndex = position
while (textBodies[currentItemIndex].type == TextBodyType.ORDERED_LIST_ITEM && currentItemIndex > 0) {
    currentItemIndex -= 1
    if (textBodies[currentItemIndex].type == TextBodyType.ORDERED_LIST_ITEM)
        itemOrdinal += 1
}
spannedText = SpannableString("$itemOrdinal. $spannedText")

Not exactly a span but there’s no span for numbered lists so you’ll have to get hacky. This is one such example.

Quote

text.setSpan(
        QuoteSpan(),
        0,
        text.length,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

QuoteSpan extends LeadingMarginSpan so the first character of the span must be at the start of a paragraph and the span will cover the whole of each start of paragraphs within its range.

Drawable

text.setSpan(
        DrawableMarginSpan(drawable, padding),
        0,
        text.length,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

DrawableMarginSpan extends LeadingMarginSpan so the first character of the span must be at the start of a paragraph and the span will cover the whole of each start of paragraphs within its range.

Typeface / Font Family

text.setSpan(
        TypefaceSpan(typeface),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

TypefaceSpan needs at least API level 28 (Android P).

Scale X

text.setSpan(
        ScaleXSpan(scale),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Relative Size

text.setSpan(
        RelativeSizeSpan(scale),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Absolute Size

text.setSpan(
        AbsoluteSizeSpan(absoluteSize),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Text Appearance / Style

text.setSpan(
        TextAppearanceSpan(context, appearanceRes),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

Mask Filter

text.setSpan(
        MaskFilterSpan(BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL)),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_INCLUSIVE)

Strikethrough

text.setSpan(
        StrikethroughSpan(),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_INCLUSIVE)

Underline

text.setSpan(
        UnderlineSpan(),
        0,
        3,
        Spannable.SPAN_EXCLUSIVE_INCLUSIVE)

Spanned vs SpannableString vs SpannableStringBuilder

These differ by whether their spans or text are mutable or not.

Spanned – Immutable span and text.

SpannableString – Mutable span, immutable text

SpannableStringBuilder – Mutable span and text

Spannable Flags

When you set a span, you must specify a flag to determine how the span behaves in terms of how it affects text that comes before and after it, as well as text that gets added later on. Some basic ones include:

SPAN_EXCLUSIVE_EXCLUSIVE

SPAN_EXCLUSIVE_INCLUSIVE

SPAN_INCLUSIVE_EXCLUSIVE

SPAN_INCLUSIVE_INCLUSIVE

Conclusion

Let me know down in the comments if you found this useful, if I missed anything, or if there are any other cheat sheets you’d like me to do in the future. As always, happy coding ༼ つ ◕_◕ ༽つ