SpannableString

概述

安卓开发中TextView 是我们最常用的控件之一,我们用TextView为我们在页面中展示文本。展示普通文本当然没有任何难度,使用TextView的setText()方法设置一个字符串就可以了,但是当我们需要在文本中展示不同格式文本的时候,设置普通的字符串就不行了。那该怎么办?当然就说到我们今天的主角了。SpannableString和SpannableStringBuilder

SpannableString

SpannableString和String一样都是一种字符串类型,他们都实现了CharSequence,所以SpannableString也可以直接使用TextView的setText()方法设置文本。SpannableString的特别之处就在于SpannableString可以打造丰富多彩的文本显示效果。SpannableString可以通过使用其方法setSpan()实现字符串各种形式风格的显示,重要的是可以指定设置的区间,也就是为字符串指定下标区间内的子字符串设置格式。

可以实现的常用效果
  1. 自定义文本中文字的字体大小(包括绝对大小和相对大小,区别看下面解释)
  2. 设置文本中文字的前景色、背景色
  3. 为文本中的文字设置下划线,删除线
  4. 设置文本中的内容上标、下标
  5. 为文字设置风格,粗体斜体等
  6. 设置图文混排,即文字中添加图片
  7. 可以为部分文本设置点击事件
setSpan()
1
2
3
public void setSpan(Object what, int start, int end, int flags) {
super.setSpan(what, start, end, flags);
}

setSpan()方法有四个参数,其中what就是所要设置的格式,start是需要设置格式的子字符串的起始下标,end就是结束下标,但并不包括这个位置。flag一共有四种值可选。如下:

  • Spannable. SPAN_INCLUSIVE_EXCLUSIVE 前面包括,后面不包括,意思就是在这段文本前部插入新的文本会应用该样式,而在文本后部插入新文本则不会应用该样式

  • Spannable. SPAN_INCLUSIVE_INCLUSIVE 前面包括,后面包括,意思就是在这段文本前部插入新的文本会应用该样式,在文本后部插入新文本也会应用该样式

  • Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 前面不包括,后面不包括

  • Spanned.SPAN_EXCLUSIVE_INCLUSIVE 前面不包括,后面包括

简单demo
1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
ForegroundColorSpan foregroundColorSpan=new ForegroundColorSpan(Color.parseColor("#FF0000"));
ss.setSpan(foregroundColorSpan,2,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

说明

SpannableString的setSpan()方法可以同时使用多个,实现多种效果叠加。

setSpan()方法中的what是最重要的一个参数,对应各种span,不同的span对应不同的样式。

常用格式效果设置

看一下不同的几种常见的span以及效果

为文本设置背景色 BackgroundColorSpan
1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
BackgroundColorSpan backgroundColorSpan=new BackgroundColorSpan(Color.parseColor("#FFFF00"));
ss.setSpan(backgroundColorSpan,2,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

为文本设置下划线以及删除线
  1. UnderlineSpan:下划线

  2. StrikethroughSpan :删除线

1
2
3
4
5
6
7
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
UnderlineSpan underlineSpan=new UnderlineSpan();//下划线span
StrikethroughSpan strikethroughSpan=new StrikethroughSpan();//删除线
ss.setSpan(underlineSpan,3,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(strikethroughSpan,0,3,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

设置文本字体 AbsoluteSizeSpan

设置的是绝对大小,直接用具体数值指定文字大小

1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
AbsoluteSizeSpan absoluteSizeSpan=new AbsoluteSizeSpan(30,true); //参数size,以size的指定像素值来设定文本大小,如果参数dip为true则以size指定的dip为值来设定文本大小。
ss.setSpan(absoluteSizeSpan,3,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

设置文本字体 RelativeSizeSpan

设置的是相对大小,在TextView原有的文字大小的基础上,相对设置文字大小

1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
RelativeSizeSpan relativeSizeSpan=new RelativeSizeSpan(0.5f);
ss.setSpan(relativeSizeSpan,3,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

设置字体样式(粗体、斜体等) StyleSpan
1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
StyleSpan styleSpan=new StyleSpan(Typeface.BOLD);
ss.setSpan(styleSpan,3,6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

设置文本中的内容上标 SuperscriptSpan 、下标SubscriptSpan

1
2
3
4
5
6
7
  TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
SuperscriptSpan superscriptSpan=new SuperscriptSpan();//上标
SubscriptSpan subscriptSpan=new SubscriptSpan();//下标
//ss.setSpan(superscriptSpan,3,5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(subscriptSpan,0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);
文本中插入图片 ImageSpan
1
2
3
4
5
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
ImageSpan imageSpan=new ImageSpan(this,R.mipmap.ic_launcher);
ss.setSpan(imageSpan,2,3,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);

给部分文本设置点击事件 ClickableSpan
1
2
3
4
5
6
7
8
9
10
11
TextView main_tv=findViewById(R.id.main_tv);
SpannableString ss=new SpannableString("其实我是一个好人");
ClickableSpan clickableSpan=new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(SecondActivity.this, "点击了", Toast.LENGTH_SHORT).show();
}
};
ss.setSpan(clickableSpan,2,4,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
main_tv.setText(ss);
main_tv.setMovementMethod(LinkMovementMethod.getInstance());

使用ClickableSpan设置点击事件,最后还需要加上main_tv.setMovementMethod(LinkMovementMethod.getInstance())这一句,不然不生效。

(此方法在需要响应用户事件时使用)

超链接

用法和点击事件一样,需要添加setMovementMethod方法附加响应

  • msp.setSpan(new URLSpan(“tel:4155551212”), 37, 39, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //电话

  • msp.setSpan(new URLSpan(“mailto:webmaster@google.com“), 39, 41, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //邮件

  • msp.setSpan(new URLSpan(“http://www.baidu.com"), 41, 43, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //网络
  • msp.setSpan(new URLSpan(“sms:4155551212”), 43, 45, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //短信 使用sms:或者smsto:
  • msp.setSpan(new URLSpan(“mms:4155551212”), 45, 47, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //彩信 使用mms:或者mmsto:
  • msp.setSpan(new URLSpan(“geo:38.899533,-77.036476”), 47, 49, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //地图
SpannableStringBuilder

SpannableStringBuilder 与 SpannableString 的区别就和string 与 stringBuilder 的区别类似。就是SpannableStringBuilder可以使用append()方法拼接,而SpannableString不可拼接。其他没有多大区别。

0%