preface

These days, when doing requirements, there is often a text that needs to be highlighted separately, and support a separate click event for that part.

There are several ways to do this:

  1. Use multiple TextViews for concatenation display
  2. Load the Html in the TextView
  3. Use SpannableString/SpannableStringBuilder

The inflexibility of the first option is not considered here.

The second option is to wrap the string with HTML tags and then use html.fromhtml (STR) to get the rendered string and set it to the TextView. If you want to pop up a local popup window or jump to another Activity, you may need to implement it through JS injection.

So the most commonly used scheme is the third one. SpannableString or SpannableStringBuilder is very powerful and can make a TextView very colorful. Let’s see.

SpannableStringBuilder and SpannableString

SpannableStringBuilder and SpannableString can both be used to display rich text, just like StringBuilder and String, SpannableStringBuilder can concatenate strings, SpannableString can’t. They both implement the Spannable interface.

Span

SpannableStringBuilder setSpan(Object What, int Start, int end, int flags) setSpan(Object What, int start, int end, int flags)

Parameter Description:

Start: indicates the start position subscript. End: indicates the end position subscript

What: Various Span instances

The following table lists some of the available spans:

Span meaning note
BackgroundColorSpan Sets the text background color Pass in a color value of type int
ForegroundColorSpan Set the text color Pass in a color value of type int
ClickableSpan Setting click events You need to inherit this class to override the onClick method
StrikethroughSpan Set strikeout effect No arguments
UnderlineSpan Set underline effect No arguments
AbsoluteSizeSpan Sets the absolute size of the text The first argument is the font size, in px, and the second argument, in dip, is false by default. When set to true, the first argument is dp
RelativeSizeSpan Sets the relative size of the text
StyleSpan Set the text to bold and italic Typeface.BOLD is in BOLD, Typeface.ITALIC is in ITALIC, and Typeface.BOLD_ITALIC is in BOLD ITALIC
ImageSpan Set the picture Replaces the text in the [start,end) range with the picture passed in as the parameter
MaskFilterSpan Embellish effects, such as BlurMaskFilter emboss
RasterizerSpan Effect of grating
SuggestionSpan It’s a placeholder
DynamicDrawableSpan Set images based on text baseline or bottom alignment
ScaleXSpan Scale on the x axis
SubscriptSpan Subscripts (used in mathematical formulas)
SuperscriptSpan Superscripts (used in mathematical formulas)
TextAppearanceSpan Text appearance (including font, size, style, and color)
TypefaceSpan The text font
URLSpan Text hyperlink

Flag: the value can be four

flag meaning
SPAN_EXCLUSIVE_EXCLUSIVE This style is not applied when new text is inserted before or after the text (not included before, not included after)
SPAN_EXCLUSIVE_INCLUSIVE Inserting new text before text does not apply the style, while inserting new text after text applies the style (not included before, included after)
SPAN_INCLUSIVE_EXCLUSIVE Inserting new text in front of text applies the style, but inserting new text after text does not.
SPAN_INCLUSIVE_INCLUSIVE This style is applied whenever new text is inserted before or after the text (included before, included after)

A. EXCLUSIVE B. INCLUSIVE C. EXCLUSIVE D. EXCLUSIVE Most use the first one, neither before nor after.

The sample

A simple example is made of a few of the commonly used Spans. The code is as follows:

class SpannableAcitivity : AppCompatActivity() {

    val textStr = "Stay up late to listen to the wind and rain, iron horse ice Falls asleep."

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_spannable)
        var builder = SpannableStringBuilder().also {
            it.append(textStr)
            it.setSpan(ForegroundColorSpan(Color.BLUE), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(BackgroundColorSpan(Color.RED), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(object : ClickableSpan() {
                override fun onClick(widget: View) {
                    Toast.makeText(this@SpannableAcitivity, "Listen to the wind and rain.", Toast.LENGTH_SHORT).show()
                }
            }, 3, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(StrikethroughSpan(), 8, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(UnderlineSpan(), 9, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(AbsoluteSizeSpan(50), 10, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(StyleSpan(Typeface.BOLD), 11, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(ImageSpan(this@SpannableAcitivity, R.mipmap.ic_launcher),
                12, 13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
        spannable_tv.text = builder
        spannable_tv.movementMethod = LinkMovementMethod.getInstance()
    }
}
Copy the code

The effect is as follows:

ClickableSpan note

When using ClickableSpan, note the following:

  1. There are default colors and sliders, so if you want to change the colors or get rid of underscores, you need to override the updateDrawState method.
@Override public void updateDrawState(@NonNull TextPaint ds) {
    super.updateDrawState(ds);
    ds.setColor(getResources().getColor(R.color.color_black));
    ds.setUnderlineText(false);
}
Copy the code
  1. After setting ClickableSpan TextView lines need to add a TextView. SetMovementMethod (LinkMovementMethod. GetInstance ()); Otherwise the ClickableSpan partial click event will not work.

  2. Setting ClickableSpan may conflict with the onClick event of the TextView itself.

The resources

Android-textview sets multiple colors and partial click events

[Android] Powerful SpannableStringBuilder