今天为什么要说 SpannableStringBuilder 这个类呢 ,这还要从之前悲催的项目经历说起,原型是这样子的,我们主要看文本,其余暂时忽略
当你看到图,是不是感觉很熟悉,因为他就是个服务条款跟隐私政策一样的勾选提交功能,如果不出意外的话,TextView 文本拼接,然后再添加上点击事件跳转,大功告成,但往往这时候都会出意外,这个服务条款很隐私政策是接口动态获取的,可能是一个也可能是两个,但此时我告诉你一个 TextView 即可搞定是不是很神奇?来看下本章最终的实现效果
Demo 源码在文章最底部,文章很长,要耐心哦
Google 官方的介绍已经很直白了,翻译过来就是,这是用于内容和标记都可以更改的文本的类。是不是第一时间想到了富文本,没错,它就是 Android 中用于创建富文本的类,它是 Spannable 接口的实现类,可以在文本中添加样式、图片、超链接等效果。
SpannableStringBuilder 和 StringBuilder 类似,也是一个动态字符串类,支持插入和删除文本,但是它可以在文本中添加多种样式,
通过源码我们可以得知,SpannableStringBuilder 主要实现了 CharSequence 和 Spannable 接口,
CharSequence 接口是在 Java 中定义的一个字符序列接口,它表示一个字符序列,可以是 String、StringBuilder、StringBuffer 等类型。CharSequence 接口是一个只读接口,提供了以下方法:
charAt(int index):返回指定位置的字符。
length():返回字符序列的长度。
subSequence(int start, int end):返回从 start 到 end-1 的字符序列子序列。
toString():返回字符序列的字符串表示形式。
CharSequence 接口的作用是为了实现字符序列的多态。通过实现该接口,不同的字符序列类型可以使用相同的方法,从而方便编程和提高代码的可读性。例如,当方法需要一个 CharSequence 类型的参数时,可以传递任何实现了 CharSequence 接口的类的对象。
在 Android 中,CharSequence 接口被广泛使用。使用 CharSequence 接口可以使程序更加灵活,提高代码的可重用性。
接着再看 Spannable 接口,通过 注释翻译过来就是标记对象可以指向的文本的接口,Spannable 接口定义了添加、移除、获取富文本样式的方法,
setSpan(Object what, int start, int end, int flags):添加一个样式 what 到 start 到 end 之间的文本中,flags 参数用于控制样式的行为。
removeSpan(Object what):从文本中移除指定的样式 what。
getSpans(int start, int end, Class type):获取从 start 到 end 之间的文本中所有类型为 type 的样式。
使用 Spannable 接口可以实现很多应用场景,例如:富文本编辑器、聊天应用中的表情符号、高亮搜索关键字等等。它可以帮助程序员实现更好的用户交互体验,提高应用的质量和可用性。
public SpannableStringBuilder append(CharSequence text) {}
该方法的作用是将一个字符序列 text 追加到 SpannableStringBuilder 实例的末尾,并返回追加后的 SpannableStringBuilder 对象
public void setSpan(Object what, int start, int end, int flags) {}
通过翻译可知
用指定的对象标记指定的文本范围。标志确定当文本为。插入到跨度范围的开始或结束处。
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个文字的样式为 start:0,end:2。而不是 end:1
前面不包括,后面包括,在Span前面输入的字符不应用 span 的效果,在后面输入的字符应用Span效果。
前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式
前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式
前面不包括,后面不包括,在 Span前后输入的字符前后都不应用 span 的效果
builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new ForegroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new BackgroundColorSpan(color), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new AbsoluteSizeSpan(sizeInPx), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new URLSpan(url), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new ImageSpan(context, resourceId), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new ScaleXSpan(scale), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new TypefaceSpan(typeface), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
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);
builder.setSpan(new ScaleXSpan(spacing), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
除了基础样式之外,您还可以自定义其它样式,例如:文本描边、文本模糊等等。只需要继承 CharacterStyle 类,并重写 updateDrawState() 方法即可。
在这个示例中,我们自定义了一个 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));
}
}
在这个示例中,我们自定义了一个 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;
}
}
在这个示例中,我们自定义了一个 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);
}
}
在这个示例中,我们自定义了一个 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);
}
}
总之,SpannableStringBuilder 是一种很方便的创建富文本的方式,可以让您在文本中添加各种样式和效果。
如果对你有所帮助的话,不妨 Star 或 Fork,青山不改,绿水长流 有缘江湖再见 ~
源码地址:RichTextDemo