Exploring Android Rich Text SpannableStringBuilder


foreword

Why do we talk about the SpannableStringBuilder class today? It starts from the previous sad project experience. The prototype is like this. We mainly look at the text and ignore the rest for the time being. When you see the picture, does it feel familiar because it
insert image description hereis The terms of service have the same check-submit function as the privacy policy. If there is no accident, TextView text splicing, and then add a click event to jump, you're done, but often there will be accidents at this time. This terms of service is very privacy policy is an interface It may be one or two dynamically acquired, but at this point I tell you that one TextView can be done, isn’t it amazing? Let’s take a look at the final implementation effect of this chapter.
insert image description here
The source code of the Demo is at the bottom of the article. Welcome to Star or Fork

1. What is SpannableStringBuilder?

Google's official introduction is already very straightforward. The translation is that this is a class for text that can be changed both in content and markup. Did you think of rich text for the first time? Yes, it is the class used to create rich text in Android. It is the implementation class of the Spannable interface, which can add styles, pictures, hyperlinks and other effects to the text.

Similar to StringBuilder, SpannableStringBuilder is also a dynamic string class that supports inserting and deleting text, but it can add a variety of styles to the text. From the source code, we can know that SpannableStringBuilder
insert image description here
mainly implements the CharSequence and Spannable interfaces.
insert image description hereThe CharSequence interface is in Java A character sequence interface defined in , which represents a character sequence, which can be String, StringBuilder, StringBuffer and other types. The CharSequence interface is a read-only interface that provides the following methods:

charAt(int index):返回指定位置的字符。
length():返回字符序列的长度。
subSequence(int start, int end):返回从 start 到 end-1 的字符序列子序列。
toString():返回字符序列的字符串表示形式。

The role of the CharSequence interface is to realize the polymorphism of character sequences. By implementing this interface, different character sequence types can use the same method, which facilitates programming and improves code readability. For example, when a method requires a parameter of type CharSequence, you can pass an object of any class that implements the CharSequence interface.

In Android, the CharSequence interface is widely used. Using the CharSequence interface can make the program more flexible and improve the reusability of the code.

insert image description hereThen look at the Spannable interface. Translated by annotations, it is an interface that marks the text that an object can point to. The Spannable interface defines methods for adding, removing, and obtaining rich text styles.

setSpan(Object what, int start, int end, int flags):添加一个样式 what 到 start 到 end 之间的文本中,flags 参数用于控制样式的行为。

removeSpan(Object what):从文本中移除指定的样式 what。

getSpans(int start, int end, Class<T> type):获取从 start 到 end 之间的文本中所有类型为 type 的样式。

Many application scenarios can be realized by using the Spannable interface, such as: rich text editor, emoticons in chat applications, highlighted search keywords, etc. It can help programmers achieve better user interaction experience and improve the quality and usability of applications.

insert image description hereFinally, let's look at the main two methods, which provide implementations for rich text

public SpannableStringBuilder append(CharSequence text) {}

The function of this method is to append a character sequence text to the end of the SpannableStringBuilder instance, and return the appended SpannableStringBuilder object
insert image description herepublic void setSpan(Object what, int start, int end, int flags) {}

Known by translation Marks
the specified range of text with the specified object. flag determines when text is . Insert at the beginning or end of the span range.
insert image description here

2. Use steps

1. Sample code

        SpannableStringBuilder builder1 = new SpannableStringBuilder();
        builder1.append("Hello World ! Do you like programming?"); // 添加普通文本
        builder1.setSpan(new StyleSpan(Typeface.BOLD), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 加粗
        builder1.setSpan(new ForegroundColorSpan(Color.RED), 6, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 字体颜色
        builder1.setSpan(new UnderlineSpan(), 12, 17, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 下划线
        builder1.setSpan(new URLSpan("https://www.baidu.com"), 18, 28, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 超链接
        builder1.setSpan(new ImageSpan(this, R.mipmap.icon_pair_number), 29, 34, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 图片
        span1Tv.setText(builder1);

2. Parameter correspondence

start: The starting position where the style takes effect, including this position

end: The position where the style ends, not including this position

 注意 :设置字符串前2个文字的样式为  start:0,end:2。而不是 end:1

flags: There are four values ​​as follows

Spannable.SPAN_EXCLUSIVE_INCLUSIVE

  前面不包括,后面包括,在Span前面输入的字符不应用 span 的效果,在后面输入的字符应用Span效果。

Spannable.SPAN_INCLUSIVE_EXCLUSIVE

  前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式

Spannable.SPAN_INCUJSIVE_INCLUSIVE

  前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE

  前面不包括,后面不包括,在 Span前后输入的字符前后都不应用 span 的效果

what: the corresponding Span

1 BackgroundColorSpan : background color
2 ForegroundColorSpan : color
3 RasterizerSpan : raster
4 StrikethroughSpan : StrikethroughSpan
5 SuggestionSpan : placeholder
6 UnderlineSpan : underline
7 AbsoluteSizeSpan : text font
8 ImageSpan : Image
9 ScaleXSpan : Horizontal scaling based on the x-axis text
10 StyleSpan : font style: bold, italic, etc.
11 SubscriptSpan : subscript
12 SuperscriptSpan : superscript
13 TypefaceSpan : font style
14 URLSpan : hyperlink
15 ClickableSpan : click event
16 AbsoluteSizeSpan font size

3.SpannableStringBuilder basic style example

1 bold
builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
2 italics
builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
3 Bold and italic
builder.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
4 strikethrough
builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
5 underscores
builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
6 font colors
builder.setSpan(new ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
7 background colors
builder.setSpan(new BackgroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
8 text size
builder.setSpan(new AbsoluteSizeSpan(sizeInPx), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
9 hyperlinks
builder.setSpan(new URLSpan(url), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
10 pictures
builder.setSpan(new ImageSpan(context, resourceId), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
11 Text scaling horizontally
builder.setSpan(new ScaleXSpan(scale), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
12 font styles
builder.setSpan(new TypefaceSpan(typeface), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
13 lines high
builder.setSpan(new LineHeightSpan() {
    
    
    @Override
    public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
    
    
        fm.descent += lineHeight - fm.bottom;
        fm.bottom = lineHeight;
    }
}, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
14 character spacing
builder.setSpan(new ScaleXSpan(spacing), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

3. SpannableStringBuilder custom style

In addition to the basic styles, you can also customize other styles, such as: text stroke, text blur, etc. Just inherit the CharacterStyle class and rewrite the updateDrawState() method.

Custom span text blur
 在这个示例中,我们自定义了一个 BlurSpan 类型,用于设置文本模糊效果。它继承自 CharacterStyle 类,重写了 updateDrawState() 方法,在该方法中设置了文本的模糊效果。

 在 updateDrawState() 方法中,我们首先创建了一个 BlurMaskFilter 对象,该对象用于设置模糊半径和模糊类型。然后,我们使用 setMaskFilter() 方法设置文本的模糊效果。
/**
 * 自定义span 文本模糊
 */
public class BlurSpan extends CharacterStyle {
    
    

    private float mRadius;

    public BlurSpan(float radius) {
    
    
        this.mRadius = radius;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
    
    
        tp.setMaskFilter(new BlurMaskFilter(mRadius, BlurMaskFilter.Blur.NORMAL));
    }
}
Custom span text background color
在这个示例中,我们自定义了一个 CustomBackgroundColorSpan 类型,用于设置文本的背景颜色。它继承自 CharacterStyle 类,重写了 updateDrawState() 方法,在该方法中设置了文本的背景颜色。
public class CustomSpan extends CharacterStyle {
    
    

    private int mBackgroundColor;

    public CustomSpan(int backgroundColor) {
    
    
        this.mBackgroundColor = backgroundColor;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
    
    
        tp.bgColor = mBackgroundColor;
    }
}
Custom span text shadow
 在这个示例中,我们自定义了一个 ShadowSpan 类型,用于设置文本阴影效果。它继承自 CharacterStyle 类,重写了 updateDrawState() 方法,在该方法中设置了文本的阴影效果。

 在 updateDrawState() 方法中,我们首先创建了一个阴影层,该层的半径、偏移量和颜色分别由 mRadius、mDx、mDy 和 mShadowColor 决定。然后,我们使用 setShadowLayer() 方法设置阴影效果。
public class ShadowSpan extends CharacterStyle {
    
    

    private float mRadius;
    private float mDx;
    private float mDy;
    private int mShadowColor;

    public ShadowSpan(float radius, float dx, float dy, int shadowColor) {
    
    
        this.mRadius = radius;
        this.mDx = dx;
        this.mDy = dy;
        this.mShadowColor = shadowColor;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
    
    
        tp.setShadowLayer(mRadius, mDx, mDy, mShadowColor);
    }
}
Custom span text stroke
 在这个示例中,我们自定义了一个 StrokeSpan 类型,用于设置文本描边效果。它继承自 CharacterStyle 类,重写了 updateDrawState() 方法,在该方法中设置了文本的描边效果。

 在 updateDrawState() 方法中,我们首先设置了文本的样式为描边样式,然后设置了描边宽度和描边颜色。
public class StrokeSpan extends CharacterStyle {
    
    

    private float mStrokeWidth;
    private int mStrokeColor;

    public StrokeSpan(float strokeWidth, int strokeColor) {
    
    
        this.mStrokeWidth = strokeWidth;
        this.mStrokeColor = strokeColor;
    }

    @Override
    public void updateDrawState(TextPaint tp) {
    
    
        tp.setStyle(Paint.Style.STROKE);
        tp.setStrokeWidth(mStrokeWidth);
        tp.setColor(mStrokeColor);
    }
}

Summarize

In short, SpannableStringBuilder is a very convenient way to create rich text, allowing you to add various styles and effects to the text.

If it is helpful to you, you may wish to Star or Fork. The green mountains will not change, and the green water will flow forever. See you in the rivers and lakes~

Source address: RichTextDemo

Guess you like

Origin blog.csdn.net/X_sunmmer/article/details/131301718