Do you want to enhance the appearance and functionality of your Android app? You can achieve this by using a versatile toolkit called Spans. Spans provide an easy way to refine your app's user experience by modifying text color, style, and even making it clickable. With over 20 span types available, you can effortlessly fine-tune text properties, harness custom visual effects, and seamlessly integrate enhanced interactivity. By using spans, you can improve the text appearance of your Android app and create interactive elements that will elevate your app's user experience.
Span types
Over 20 types of spans are available; we will describe the commonly used ones. If you want a list of all kinds, go to the official Android documentation.
Some span types can be added to individual characters, and others must be added to an entire paragraph.
So, we divide spans into two categories :
-
Character Affecting Spans (Can be applied to individual characters)
-
Appearance Affecting Spans (color, background, style, size),
-
Metric Affecting Spans (font, alignment, line height)
-
-
Paragraph Affecting Spans (Must be applied to an entire section)
You can also create your custom spans to apply any styling or functionality to your text; we will look later at how to implement it in your code.
Span implementation
Span can be created with any of these classes in the Android library :
- SpannedString is a type of text that cannot be changed once created (immutable). It has a fixed length and style. You can use it to show some text that is already formatted and does not need modification.
- SpannableString is a type of text that cannot be changed once created (immutable).It has a fixed length but style can change. You can apply different styles and formatting to different portions of the text.
- SpannableStringBuilder is a type of text that can be changed in its content and style. It has a variable length and style. You can use it to perform operations on the text and its style, such as adding, removing, replacing, etc.
Select the appropriate class based on your requirements. For instance, use SpannableString to showcase formatted text that remains static. On the other hand, if you need to enable text editing and formatting changes, go for SpannableString. When text manipulation and formatting adjustments are required programmatically, SpannableStringBuilder becomes the ideal choice.
To apply a span, call
setSpan(Object span, int start, int end, int flags)
Object spanto apply the text toint startrepresents the beginning position of the text where the span should be applied.int endrepresents the position immediately after the last character to which the span will be applied. In other words, the span will apply up to, but not including, the character at the position indicated by the end.int flagsthe "flag" value determines how a text span reacts to the inserted text within its range. We can use theSpannable.SPAN_EXCLUSIVE_INCLUSIVEorSpannable.SPAN_EXCLUSIVE_EXCLUSIVE.Spannable.SPAN_EXCLUSIVE_INCLUSIVEcan help you when you apply a text span with this flag to a specific range of text, such as a substring, and then insert new text within that range, the span will automatically expand to include the newly inserted text. In other words, any formatting or properties associated with the span will apply to both the original text and the inserted text. This can be useful when you want the formatting of a span to encompass any modifications made within its boundaries.Spannable.SPAN_EXCLUSIVE_EXCLUSIVE: When you apply a text span with this flag to a range of text and insert new text within that range, the span will remain fixed to its initial boundaries and not include the inserted text. In other words, the inserted text will not inherit the formatting or properties of the span. This is useful when you want to maintain a specific formatting only on the original text and prevent any inserted text from inheriting that formatting.
ForegroundColorSpan
If you need to add a different color to a specific part of a text, then ForegroundColorSpan is the span type to use. It belongs to a Character Affecting Spans, so that means we can apply it to any part of a desired part of a text.
As you see in the picture, a red color is applied to the text part, where we set the color with an index from the start of a character to the last character number.
val text = "Practice makes progress. Start now!"
val spannableString = SpannableString(text)
val start = 25 // Start index of the text portion
val end = 35 // End index of the text portion
val color = Color.RED // Color for the text portion
val colorSpan = ForegroundColorSpan(color)
spannableString.setSpan(colorSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
sampleSpanColorTextView.text = spannableString //sets text to TextViewBackgroundColorSpan
For any background text coloring with BackgroundColorSpan, you can set any crucial words to stand out. This can be used to visually highlight or emphasize certain words, phrases, or sentences, making them stand out from the rest of the text.
To apply BackgroundColorSpan, you need to create an instance of the span and then associate it with the desired portion of text using the setSpan() method of a SpannableString or SpannableStringBuilder.
You can customize the background color by specifying the desired color using the Color class, such as Color.RED, Color.BLUE, or custom color values. It is also a part of a Character Affecting Spans.
val text = "Never give up on learning"
val spannableString = SpannableString(text)
val start = 0 // Start index of the text portion
val end = text.length // End index of the text portion
val bgColor = Color.YELLOW // Background color for the text portion
val bgColorSpan = BackgroundColorSpan(bgColor)
spannableString.setSpan(bgColorSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
binding.sampleSpanBackgroundTV.text = spannableStringStyleSpan
With the StyleSpan class, you can apply text styles such as bold, italic, underline, or strike-through to any part of a text. It is also a part of a Character Affecting Spans.
val text = "This is a bold italic text style"
val spannableString = SpannableString(text)
val start = 10 // Start index of the text portion
val end = 32 // End index of the text portion
// Apply bold and italic styles
val styleSpan = StyleSpan(Typeface.BOLD_ITALIC)
spannableString.setSpan(styleSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
binding.sampleSpanStyleTV.text = spannableStringClickableSpan
ClickableSpan is a class in Android that allows you to make a part of a text view clickable and perform some action when clicked. It is a subclass of CharacterStyle.
To use ClickableSpan, create an instance and override the onClick(View) method to define what happens when the span is clicked. You also need to set the span on a SpannableString using the setSpan(Object, int, int, int) method, where you specify the start and end index of the span within the string. Then you need to set the SpannableString as the text of a text view and set a movement method of LinkMovementMethod on the text view to enable clicking.
val text = "Click me for an action"
val spannableString = SpannableString(text)
val start = 0 // Start index of the text portion
val end = text.length // End index of the text portion
// Define the action to be performed when the text is clicked
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
// Action to perform when the text is clicked
Toast.makeText(requireContext(), "Text Clicked!", Toast.LENGTH_SHORT).show()
}
}
spannableString.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
// Enable clickable behavior on the TextView
binding.sampleSpanClickableTV.movementMethod =
android.text.method.LinkMovementMethod.getInstance()
binding.sampleSpanClickableTV.text = spannableStringCustom span
If you need the functionality of a span that isn't already provided in existing Android span classes, you can create your custom span implementation. First, you must decide what this span will change to know which base classes to extend and interfaces to implement. For reference, you can check the table below :
In this custom class, we will change the text color to red and make larger text with bold style.
We created a new class with CustomSpan that extends RelativeSizeSpan(float proportion) with three parameters :
size: a Float value representing the relative size of the text span.color: a @ColorInt annotation indicating the color of the text span.isBoldText: a Boolean flag indicating whether the text should be displayed in bold.
The class overrides the updateDrawState method, which is responsible for updating the visual appearance of the text. This method is called when the text is drawn on the screen. Inside the updateDrawState method:
- The
super.updateDrawState(textPaint)call invokes the parent class's implementation of theupdateDrawStatemethod, which sets up the relative text size. textPaint?.color = colorsets the text color of the span using the provided color.textPaint.isFakeBoldText = isBoldTextsets the boldness of the text span based on theisBoldTextflag.
class CustomSpan(
size: Float,
@ColorInt private val color: Int,
val isBoldText: Boolean
) : RelativeSizeSpan(size) {
override fun updateDrawState(textPaint: TextPaint) {
super.updateDrawState(textPaint)
textPaint?.color = color
textPaint.isFakeBoldText = isBoldText
}
}
We then add this custom class as a parameter to the setSpan method.
val customSpan = CustomSpan(3.5f, Color.RED, true)
val text = SpannableString("Custom span text")
text.setSpan(customSpan, 0, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
binding.sampleSpanCustom.text = text
}
Result of the above custom span code :
Conclusion
Spans are a handy tool for enhancing the appearance of text and making it stand out. They are beneficial when we need to apply rich text formatting, create complex text layouts, add custom styling, or use various effects to text, such as changing the color size or making it clickable. Creating a custom reusable span class is recommended if you are looking for consistent text formatting throughout your app. This ensures that formatting remains consistent across the app and makes it easier to manage text styling.