1、简单介绍
SpannableStringBuilder这个类可以使文本的内容和标记都可以改变。当我们要为TextView或者Edittext里面的文字加入加入一些效果,如下划线,颜色标识,超链接等,类似word文档一样。这时候可以用到SpannableStringBuilder ,SpannableStringBuilder是 android.text里面的一个类,功能非常强大。主要的一个方法就是setSpan (Object what, int start, int end, int flags),这个方法的作用就是在把某个范围内的文字替换成某种东西。
2、SpannableString与SpannableStringBuilder区别
它们的区别在于 SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个 SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String;
3、SetSpan()
void setSpan (Object what, int start, int end, int flags)
函数意义:给SpannableString或SpannableStringBuilder特定范围的字符串设定Span样式,可以设置多个(比如同时加上下划线和删除线等),Falg参数标识了当在所标记范围前和标记范围后紧贴着插入新字符时的动作,即是否对新插入的字符应用同样的样式。
参数说明:
object what :对应的各种Span,后面会提到;
int start:开始应用指定Span的位置,索引从0开始
int end:结束应用指定Span的位置,特效并不包括这个位置。比如如果这里数为3(即第4个字符),第4个字符不会有任何特效。从下面的例子也可以看出来。
int flags:取值有如下四个
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE :前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE :前面包括,后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE :前后都包括。
4、用法详解
SpannableString ss = new SpannableString("红色打电话斜体删除线绿色下划线图片:.");
//用颜色标记文本
//setSpan时需要指定的 flag,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括).
ss.setSpan(new ForegroundColorSpan(Color.RED), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//用超链接标记文本
ss.setSpan(new URLSpan("tel:4155551212"), 2, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//用样式标记文本(斜体)
ss.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 5, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//用删除线标记文本
ss.setSpan(new StrikethroughSpan(), 7, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//用下划线标记文本
ss.setSpan(new UnderlineSpan(), 10, 16, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//用颜色标记
ss.setSpan(new ForegroundColorSpan(Color.GREEN), 10, 13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//获取Drawable资源
Drawable d = ContextCompat.getDrawable(this,R.mipmap.ic_launcher);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
//创建ImageSpan
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
//用ImageSpan替换文本
ss.setSpan(span, 18, 19, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
txtInfo.setText(ss);
txtInfo.setMovementMethod(LinkMovementMethod.getInstance()); //实现文本的滚动
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(ss);
txtInfo.setText(stringBuilder);
5、简单示例
主要代码
- 重写Span
package com.tobin.tobintest;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.style.ReplacementSpan;
/**
* @author Tobin
*/
public class RoundedBackgroundSpan extends ReplacementSpan {
private static int CORNER_RADIUS = 8;
private int backgroundColor = 0;
private int textColor = 0;
public RoundedBackgroundSpan(int backgroundColor,int textColor) {
super();
this.backgroundColor = backgroundColor;
this.textColor = textColor;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
Paint.FontMetrics fm = paint.getFontMetrics();
// RectF rect = new RectF(x, top, x + measureText(paint, text, start, end), bottom);
// fm.bottom - fm.top 解决设置行距(android:lineSpacingMultiplier="1.2")时背景色高度问题
RectF rect = new RectF(x, top, x + measureText(paint, text, start, end), fm.bottom - fm.top );
paint.setColor(backgroundColor);
canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint);
paint.setColor(textColor);
canvas.drawText(text, start, end, x, y, paint);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm){
return Math.round(paint.measureText(text, start, end));
}
private float measureText(Paint paint, CharSequence text, int start, int end) {
return paint.measureText(text, start, end);
}
}
- Activity
public class MainActivity extends AppCompatActivity {
private TextView txtInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] tags = {"精华", "活动","推荐"};
txtInfo = (TextView) findViewById(R.id.txt_test);
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
for (String tag : tags) {
String thisTag = " " + tag + " ";
stringBuilder.append(thisTag);
RoundedBackgroundSpan span;
if("活动".equals(tag)){
span= new RoundedBackgroundSpan(ContextCompat.getColor(this,R.color.test3), ContextCompat.getColor(this,R.color.white));
}else if ("推荐".equals(tag)){
span= new RoundedBackgroundSpan(ContextCompat.getColor(this,R.color.test2), ContextCompat.getColor(this,R.color.white));
}else{
span= new RoundedBackgroundSpan(ContextCompat.getColor(this,R.color.test1), ContextCompat.getColor(this,R.color.white));
}
stringBuilder.setSpan(span, stringBuilder.length() - thisTag.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.append(" ");
}
stringBuilder.append("王宝强凌晨宣布离婚,妻子劈腿经纪人。");
txtInfo.setText(stringBuilder);
}
}