一.导引
1.适用对象
没有接触过SpannableString的人
听过但是不熟悉不了解SpannableString的人。
2.教程结构
- 简介
- SpannableString
- SpannableStringBuilder
- 实战部分
- 总结和感想(作者瞎逼逼时间)
二.正文
1.简介
SpannableString和SpannableStringBuilder的关系类似于String和StringBuilder。前者不可变,后者可变。所以两者的使用方法基本相同。
功能在于给一串普通的字符串加上颜色,大小背景等样式和特殊事件(点击事件)。下面先上一个例子
这个例子很普通,小伙伴们一看可能会觉得这不就是几个TextView吗?
没错,这就是TextView。但不是几个,而是一个,只用一个TextView显示出这串花花绿绿的文字是不是很🐂的感觉呢?
这个时候可能有小伙伴会说:“一个TextView?也简单啊,我写成html,加点color,background样式,然后用 Html.fromHtml( ) 一下还不是轻轻松松,要你这破Span啥啥的干啥用!”
没错,这样子是能实现这个效果,但是你们不觉得一串串html的代码硬编码在Android项目里很难看么!而且经过我对 Html.fromHtml( ) 的源码的研究发现,这个方法并没有什么神秘之处(能够DuangDuang的就给文字加特技,呸! 加样式)。
mSpannableStringBuilder = new SpannableStringBuilder();
if (end == start) {
mSpannableStringBuilder.removeSpan(obj[i]);
} else {
mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH);
}
上面是截取了部分Html.fromHtml( ) 方法调用的源码。细心的小伙伴们肯定发现了,这里面出现了个SpannableStringBuilder()。所以一切真相大白了,原来该方法将html解析之后通过SpannableStringBuilder来给他添加样式。看到这的小伙伴们是不是学会用SpannableStringBuilder很有用了呢!😁
2.SpannableString
SpannableString ss=new SpannableString("这是另外一串普通的文字");
ForegroundColorSpan colorSpan=new ForegroundColorSpan(Color.RED);
ss.setSpan(colorSpan,0,5,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ss);
使用方法和SpannableStringBuilder类似,简单举个例子,不做过多的解释。
3.SpannableStringBuilder
本章的主角,SpannableString的好基友。
class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable,
Appendable, GraphicsOperations{}
//这里主要注意CharSequence和Spannable
//继承自Spannable,赋予了它给文本设定样式的基础功能
//实现接口CharSequence则代表了他能在很多地方使用,比如TextView的setText方法的参数就是CharSequence对象
下面来看主要的两个方法
public SpannableStringBuilder append(CharSequence text) {}
//将文本添加到SpannableStringBuilder中,和StringBuilder的append方法功能类似
public void setSpan(Object what, int start, int end, int flags) {}
用于设置样式的核心方法。参数:
- what
各种Span,不同的Span对应不同的样式,具体有如下:
- ForegroundColorSpan : 设置文本前景色(文本颜色)
- BackgroundColorSpan : 设置背景颜色
- AbsoluteSizeSpan : 设置绝对的文字大小,px单位
- ClickableSpan : 为文字添加点击事件(类似于微信朋友圈评论列表中用户的昵称点击事件就可以用这个实现)
- DynamicDrawableSpan :
- ImageSpan : 文文本添加图片
- RelativeSizeSpan : 设置相对文字大小,为倍数,相对于其他文字的大小
- StrikethroughSpan : 添加删除线
- SubscriptSpan : 设置下标文字
- SuperscriptSpan : 设置上标文字
- URLSpan : 文字设定超链接
- UnderlineSpan : 设置下划线
- start
样式生效的开始位置,包括该位置
3)end
样式结束的位置,不包括该位置,所以设定一串文字中前3个文字的样式时start:0,end:3。而不是end:2 - flags
这几个参数中最难懂最麻烦最难搞的一个参数。
主要有以下四个值:
- Spannable.SPAN_EXCLUSIVE_INCLUSIVE:在 Span前面输入的字符不应用 span 的效果,在后面输入的字符应用Span效果。
- Spannable.SPAN_INCLUSIVE_EXCLUSIVE:在 Span前面输入的字符应用 span 的效果,在后面输入的字符不应用Span效果。
- Spannable.SPAN_INCUJSIVE_INCLUSIVE:在 Span前后输入的字符都应用 span 的效果。
-
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:在 Span前后输入的字符前后都不应用 span 的效果。
看得小伙伴们一头雾水对吧,前前后后用不用的,啥玩意?
接下来我上两张图让大家看懂这四个flag的区别
这是对同一段文字设置相同的span,区别在于flag的不同,4个的效果是不是一毛一样呢?
这张图片中的 “zz” 是在EditText中输入进去的,小伙伴们结合上面对4个flag的介绍,是不是能理解了呢?
//部分代码
final String baseString="这是开始的文字";
SpannableStringBuilder sb;
ForegroundColorSpan span;
sb=new SpannableStringBuilder();
sb.append(baseString);
span=new ForegroundColorSpan(Color.RED);
sb.setSpan(span,2,4,Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
et.setText(sb);
sb=new SpannableStringBuilder();
sb.append(baseString);
span=new ForegroundColorSpan(Color.RED);
sb.setSpan(span,2,4,Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
et2.setText(sb);
sb=new SpannableStringBuilder();
sb.append(baseString);
span=new ForegroundColorSpan(Color.RED);
sb.setSpan(span,2,4,Spanned.SPAN_INCLUSIVE_INCLUSIVE);
et3.setText(sb);
sb=new SpannableStringBuilder();
sb.append(baseString);
span=new ForegroundColorSpan(Color.RED);
sb.setSpan(span,2,4,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
et4.setText(sb);
4.激动人心的实战时刻
ForegroundColorSpan的使用:
SpannableStringBuilder sb=new SpannableStringBuilder();
sb.append("红色绿色蓝色");
ForegroundColorSpan colorSpan=new ForegroundColorSpan(Color.RED);
sb.setSpan(colorSpan,0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
colorSpan=new ForegroundColorSpan(Color.GREEN);
sb.setSpan(colorSpan,2,4,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
colorSpan=new ForegroundColorSpan(Color.BLUE);
sb.setSpan(colorSpan,4,6,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(sb);
效果:
花花绿绿的最好看了☺
ImageSpan:
SpannableStringBuilder sb=new SpannableStringBuilder();
sb.append("图片前面的变成图片了");
ImageSpan span=new ImageSpan(this,R.mipmap.ic_launcher);
sb.setSpan(span,0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//替换掉了前两个文字,所以添加的图片占用两个文字的宽度
tv.setText(sb);
效果:
说好的大家一起做文字的,你却偷偷整容成图片了,哼!
ClickableSpan:
SpannableStringBuilder sb=new SpannableStringBuilder();
sb.append("我们中有两个文字可以点击哦");
ClickableSpan span=new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(MainActivity.this,"你点击了我",Toast.LENGTH_LONG).show();
}
};
sb.setSpan(span,0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(sb);
//设置了点击事件后请加上这句,不然点击事件不起作用
tv.setMovementMethod(LinkMovementMethod.getInstance());
效果:
别忘了这一句:tv.setMovementMethod(LinkMovementMethod.getInstance());
很重要。
另外给文字设置点击事件之后会自动给文字加上下划线,可以使用如下方式去除这个默认的下划线:
//自定义类继承自ClickableSpan。用该类来代替使用
public abstract class NoLineClickSpan extends ClickableSpan {
public NoLineClickSpan() {
super();
}
@Override
public void updateDrawState(TextPaint ds) {
/**set textColor**/
ds.setColor(ds.linkColor);
/**Remove the underline**/
ds.setUnderlineText(false);
}
@Override
public abstract void onClick(View widget);
}
由于篇幅所限,在此就介绍这么多的Span使用例子,其他几个Span的适用方法还请小伙伴们自己探索,毕竟自己动手学的快嘛(我才不会说是我自己懒😕!)
另外小伙伴们是不是觉得new出一个又一个的span很麻烦呢,而且手动计算start,end很麻烦呢?下面给大家推荐一个简单的辅助类。
好了,以上都是广告时间,下面进入正文:
欢迎小伙伴使用我写的一个辅助工具类,gayhub地址:https://github.com/zYinux/SpecialString。
使用了该库之后设置样式只需要:
//构建SpecialStyle 用来设置样式的核心类
SpecialStyle style=new SpecialStyle();
SpecialStringBuilder sb=new SpecialStringBuilder();
//设置文本颜色为黑色。第二个参数save的意思是代表该样式是否应用到下一段文字,如果不传则为true
style.setColor(Color.BLACK,false);
//为文字设置样式
sb.append("售价:",style);
style.setColor(Color.RED,false);
sb.append("¥99.99 ",style);
//设置颜色背景和点击事件样式
//点击事件默认为不应用于下一段文字
style.setColor(Color.GREEN,false)
.setBackgroundColor(Color.rgb(200,200,200),false)
.setClickable(new ClickableStyle.OnClick() {
@Override
public void onClick(View widget) {
Toast.makeText(MainActivity.this,"开始抢购",Toast.LENGTH_SHORT).show();
}
});
sb.append("立即抢购",style);
//为TextView设置刚刚构建的文本
tv.setText(sb.getCharSequence());
//如果为文字添加了点击事件,请添加这一句,否则点击事件不生效
tv.setMovementMethod(LinkMovementMethod.getInstance());
是不是简单了很多了呢?终于不用去理会那些烦人的start,end,flag了。具体使用方法请大家转到GitHub查看,方便的话欢迎小伙伴给个star,谢谢啦。
5.瞎逼逼时间
小伙伴们好!
我叫 zYinux ,取这个网名是为了致敬IT界的大佬的项目Linux。可惜目前我还是一个刚入门的菜鸟,希望能通过自己的努力攀爬到更高的境界。这是我写的第二篇博客,上一篇已是1年前了,接下来会努力一个月出一篇博客。文笔不好望大家见谅,希望看到这里的小伙伴已经学会了上面的知识,如果小伙伴发现了教程中有错误和遗漏之处,欢迎联系我指正。
QQ交流群:589184413