Spannable实现TextView/EditText的富文本显示

  |  

TextView和EditText都可以设置纯文本的字符串,但是当一个字符串中需要设置不同的文字格式或者插入图片时,我们不可能去设置多个TextView+ImageView来实现,那样要累死了。(话说,刚开始我就是动态添加四个TextView来实现一个效果,好囧)。我们知道,方法setText(CharSequence text)中接收的是CharSequence。而SpannableString和SpannableStringBuilder是其实现类,是可以直接赋值的,并且,两者的setSpan()方法可以设置一些格式对象(例如字体大小,下划线,替换为图片,等),这就可以实现富文本了。

TextView和EditText灵活设置文字格式

TextView和EditText都可以设置纯文本的字符串,但是当一个字符串中需要设置不同的文字格式或者插入图片时,我们不可能去设置多个TextView+ImageView来实现,那样要累死了。(话说,刚开始我就是动态添加四个TextView来实现一个效果,好囧)。我们知道,方法setText(CharSequence text)中接收的是CharSequence。而SpannableString和SpannableStringBuilder是其实现类,是可以直接赋值的,并且,两者的setSpan()方法可以设置一些格式对象(例如字体大小,下划线,替换为图片,等),这就可以实现富文本了。

接口 Spannable—>Spanned—>CharSequence

实现子类:

|–Editable

|–SpannableString

|–SpannableStringBuilder(–>Editale)

Spannable中定义了抽象方法:setSpan(Object what, int start, int end, int flags)和removeSpan(Object what)。这两个方法实现了对字符串的灵活编辑。

可以实现一下效果:

各Span的简单应用

以下是一些常用到的一些Span:

  • BackgroundColorSpan
  • ForegroundColorSpan
  • StyleSpan
  • TypefaceSpan
  • ImageSpan
  • URLSpan
  • UnderlineSpan
  • StrikethroughSpan(删除线)

具体没啥说的,见名知意,直接看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
private void setSpan() {
SpannableString spannableString = new SpannableString("君不见黄河之水天上来,");
SpannableString spannableString2 = new SpannableString("奔流到海不复回。");
SpannableString spannableString3 = new SpannableString("君不见高堂明镜悲白发,");
SpannableString spannableString4 = new SpannableString("朝如青丝暮成雪。");
SpannableString spannableString5 = new SpannableString("人生得意须尽欢。");
SpannableString spannableString6 = new SpannableString("莫使金樽空对月。");
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.GREEN);
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.CYAN);// 同ForegroundColorSpan应用一样
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(32,true);// 32dp
UnderlineSpan underlineSpan = new UnderlineSpan();
// 文本字体格式,加粗,倾斜
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD_ITALIC);
// 这四种flags的显示效果是一样的,包前不包后
spannableString.setSpan(foregroundColorSpan,1,5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableString.setSpan(styleSpan, 1, 5, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
spannableString2.setSpan(underlineSpan, 1, 5, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
spannableString3.setSpan(absoluteSizeSpan, 1, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableString4.setSpan(backgroundColorSpan, 1, 5, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ImageSpan imageSpan = new ImageSpan(this,R.mipmap.iv_lyf);
spannableString5.setSpan(imageSpan, 1, 4, Spanned.SPAN_COMPOSING);
Drawable drawable = getResources().getDrawable(R.mipmap.iv_lyf);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth()/3, drawable.getIntrinsicHeight()/3);//缩小为1/3
ImageSpan imageSpan1 = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
spannableString6.setSpan(imageSpan1,1,5,Spanned.SPAN_COMPOSING);
textView.setText(spannableString);
textView2.setText(spannableString2);
textView3.setText(spannableString3);
textView4.setText(spannableString4);
textView5.setText(spannableString5);
textView6.setText(spannableString6);
// 以上四种span对于新增加的文字有效果
// editText.setText(spannableString);// Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 在span的文字前后新加文字都不会有span设置的效果
// editText.setText(spannableString2);// Spanned.SPAN_EXCLUSIVE_INCLUSIVE 在span的文字前后新加文字,前边无效果,后边会复用效果
// editText.setText(spannableString3);// Spanned.SPAN_INCLUSIVE_EXCLUSIVE 在span的文字前后新加文字,前边会复用效果,后边无效果
editText.setText(spannableString4);// Spanned.SPAN_INCLUSIVE_INCLUSIVE 在span的文字前后新加文字,前边和后边都会复用效果
}

以上是SpannableString的应用,还有一个SpannableStringBuilder,他们两个区别就是,后者可以通过append()方法动态添加文本。其他用法相同。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void setSpan2() {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("天生我材必有用,");
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
StrikethroughSpan strikethroughSpan =new StrikethroughSpan();
spannableStringBuilder.setSpan(foregroundColorSpan,0,3,Spanned.SPAN_COMPOSING);
spannableStringBuilder.append("千金散尽还复来。");
spannableStringBuilder.setSpan(strikethroughSpan,3,12,Spanned.SPAN_COMPOSING);
textView7.setText(spannableStringBuilder);
}

利用ClickableSpan实现可点击文本

在项目中,点赞人名的依次排列并可点击的场景是很常用的,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
private void setMoreLikers(){
// 构造多个超链接的html, 通过选中的位置来获取用户名
StringBuilder sbBuilder = new StringBuilder();
for (int i = 0; i < 15; i++) {
sbBuilder.append("liker" + i + "、");
}
String likers = sbBuilder.substring(0, sbBuilder.lastIndexOf("、")).toString();
textView8.setMovementMethod(LinkMovementMethod.getInstance());//
textView8.setText(addClickablePart(likers), TextView.BufferType.SPANNABLE);
}
/**
* ClickableSpan 可点击的文本
* @param str
* @return
*/
private SpannableStringBuilder addClickablePart(String str) {
Drawable drawable = getResources().getDrawable(R.mipmap.ic_like);
drawable.setBounds(0,0,30,30);// 设置大小
// 赞的图标
ImageSpan span = new ImageSpan(drawable, DynamicDrawableSpan.ALIGN_BASELINE);
SpannableString spanStr = new SpannableString("l");// 被替换的
spanStr.setSpan(span, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
// 将赞的图标和赞的人名拼接
SpannableStringBuilder ssb = new SpannableStringBuilder(spanStr);
ssb.append(str) ;
String[] likers = str.split("、");
if (likers.length > 0) {
for (int i = 0; i < likers.length; i++) {
final String name = likers[i];
final int start = str.indexOf(name) + spanStr.length();
ssb.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
// 设置文本颜色
ds.setColor(Color.RED);
// 去掉下划线
ds.setUnderlineText(false);
ds.setTextSize(30.0f);
}
}, start, start + name.length(), Spanned.SPAN_COMPOSING);
}
}
return ssb.append("赞了您.");
}

URLSpan用法

URLSpan urlSpan = new URLSpan(“tel:10086”);

URLSpan默认都设置了ClickableSpan,都是可点击的。

“tel:”:电话

“mailto:”:邮件

“http:”:网址

“sms:”:短信

“geo:”:地图(需要fq)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 点击电话超链接,拨打电话
*/
private void setUrlSpan(){
SpannableString spannableString = new SpannableString("电话");
final URLSpan urlSpan = new URLSpan("tel:10086");
spannableString.setSpan(urlSpan, 0, 2, Spanned.SPAN_COMPOSING);
textView9.setMovementMethod(LinkMovementMethod.getInstance());
textView9.setText(spannableString);
}
/**
* 网址超链接 默认是可点击跳转的
*/
private void setUrlSpan2(){
SpannableString spannableString = new SpannableString("网址");
final URLSpan urlSpan2 = new URLSpan("http://www.csdn.net");
spannableString.setSpan(urlSpan2, 0, 2, Spanned.SPAN_COMPOSING);
textView10.setMovementMethod(LinkMovementMethod.getInstance());
textView10.setText(spannableString);
}
文章目录
  1. 1. TextView和EditText灵活设置文字格式
  2. 2. 各Span的简单应用
  3. 3. 利用ClickableSpan实现可点击文本
  4. 4. URLSpan用法
,