SpannableString、SpannableStringBuilder与String的关系

1.1 概述

SpannableString、SpannableStringBuilder基本上与String差不多,也是用来存储字符串,但它们俩的特殊就在于有一个SetSpan()函数,能给这些存储的String添加各种格式或者称样式(Span),将原来的String以不同的样式显示出来,比如在原来String上加下划线、加背景色、改变字体颜色、用图片把指定的文字给替换掉,等等。所以,总而言之,SpannableString、SpannableStringBuilder与String一样, 首先也是传字符串,但SpannableString、SpannableStringBuilder可以对这些字符串添加额外的样式信息,但String则不行。

它们的区别在于 SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个 SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String。

| 功能 | String |SpannableString | SpannableStringBuilder|
|–|–|–|–|–|
| 存储字符串 | 是 | 是 | 是 |
| 通过setSpan()能给存储的字符串添加各种样式(Span),比如颜色背景等 | 否 | 是 | 是 |
| 创建之后是否可以更改其内容并跟随变化 | 否 | 否 | 是

1.2 setSpan()方法介绍

void setSpan (Object what, int start, int end, int flags)

Object what

对应各种Span

int start

开始应用指定Span的位置,索引从0开始

int end

结束应用指定Span的位置,特效并不包括这个位置

int flags

指定范围前后输入新的字符时,会不会应用效果

flags参数介绍

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE

前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式

Spannable.SPAN_EXCLUSIVE_INCLUSIVE

前面不包括,后面包括,即仅在范围字符的后面插入新字符时会应用新样式

Spannable.SPAN_INCLUSIVE_EXCLUSIVE

前面包括,后面不包括

Spannable.SPAN_INCLUSIVE_INCLUSIVE

前后都包括

1.3 Span汇总

用途

Span

设置字体颜色

ForegroundColorSpan

设置字体背景颜色

BackgroundColorSpan

设置字体大小

AbsoluteSizeSpan

设置字体为粗体、斜体

StyleSpan

设置字体删除线

StrikethroughSpan

设置字体下划线

UnderlineSpan

将文字替换成图片

ImageSpan

点击文字可以打开一个URL

URLSpan

文字可点击

ClickableSpan



1.3.1 设置字体颜色 ForegroundColorSpan
String str = "Hello World!";
SpannableStringBuilder ssb = new SpannableStringBuilder(str);
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ContextCompat.getColor(this, R.color.colorAccent));
ssb.setSpan(foregroundColorSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTv.setText(ssb);

Android app bundle 如何控制string资源 android spannablestringbuilder_android

1.3.2 点击文字可以打开一个URL URLSpan
String str = "点击百度!";
SpannableStringBuilder ssb = new SpannableStringBuilder(str);
URLSpan urlSpan = new URLSpan("https://www.baidu.com/");
ssb.setSpan(urlSpan, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTv.setMovementMethod(LinkMovementMethod.getInstance());
mTv.setText(ssb);

Android app bundle 如何控制string资源 android spannablestringbuilder_ide_02

1.3.3 将文字替换成图片 ImageSpan
String str = "img ImageSpan!";
SpannableStringBuilder ssb = new SpannableStringBuilder(str);
ImageSpan imageSpan = new ImageSpan(this,R.mipmap.ic_launcher, ImageSpan.ALIGN_BOTTOM);
ssb.setSpan(imageSpan, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTv.setText(ssb);

Android app bundle 如何控制string资源 android spannablestringbuilder_android_03

1.3.4 文字可点击 ClickableSpan
String str = "点击事件 ImageSpan!";
SpannableStringBuilder ssb = new SpannableStringBuilder(str);
MClickableSpan mClickableSpan = new MClickableSpan(new MClickableSpan.OnClickListener() {
    @Override
    public void OnClick(View view) {
        Toast.makeText(MainActivity.this, "点击事件", Toast.LENGTH_SHORT).show();
    }
});
ssb.setSpan(mClickableSpan, 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// 凡是有要执行的动作,都必须设置MovementMethod对象
mTv.setMovementMethod(LinkMovementMethod.getInstance());
mTv.setHighlightColor(ContextCompat.getColor(this, R.color.colorAccent));
mTv.setText(ssb);

static class MClickableSpan extends ClickableSpan {

    private OnClickListener onClickListener;

    interface OnClickListener {
        void OnClick(View view);
    }

    public MClickableSpan(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    @Override
    public void updateDrawState(@NonNull TextPaint ds) {
        ds.setColor(0xFF5394f5);
        ds.setUnderlineText(false);
        ds.clearShadowLayer();
        ds.bgColor = Color.TRANSPARENT;
    }

    @Override
    public void onClick(@NonNull View widget) {
        onClickListener.OnClick(widget);
    }
}

Android app bundle 如何控制string资源 android spannablestringbuilder_android_04

参考资料

SpannableString与SpannableStringBuilderAndroid中span总结

TextView显示丰富多彩的文字(一)TextView显示丰富多彩的文字(二)TextView显示丰富多彩的文字(三)