一.導(dǎo)引
1.適用對(duì)象
沒(méi)有接觸過(guò)SpannableString的人
聽(tīng)過(guò)但是不熟悉不了解SpannableString的人吵冒。
2.教程結(jié)構(gòu)
- 簡(jiǎn)介
- SpannableString
- SpannableStringBuilder
- 實(shí)戰(zhàn)部分
- 總結(jié)和感想(作者瞎逼逼時(shí)間)
二.正文
1.簡(jiǎn)介
SpannableString和SpannableStringBuilder的關(guān)系類(lèi)似于String和StringBuilder概荷。前者不可變,后者可變衷畦。所以?xún)烧叩氖褂梅椒ɑ鞠嗤?/p>
功能在于給一串普通的字符串加上顏色竹海,大小背景等樣式和特殊事件(點(diǎn)擊事件)晰骑。下面先上一個(gè)例子
這個(gè)例子很普通敛劝,小伙伴們一看可能會(huì)覺(jué)得這不就是幾個(gè)TextView嗎?
沒(méi)錯(cuò)纷宇,這就是TextView夸盟。但不是幾個(gè),而是一個(gè)像捶,只用一個(gè)TextView顯示出這串花花綠綠的文字是不是很??的感覺(jué)呢上陕?
這個(gè)時(shí)候可能有小伙伴會(huì)說(shuō):“一個(gè)TextView?也簡(jiǎn)單啊拓春,我寫(xiě)成html释簿,加點(diǎn)color,background樣式硼莽,然后用 Html.fromHtml( ) 一下還不是輕輕松松庶溶,要你這破Span啥啥的干啥用!”
沒(méi)錯(cuò),這樣子是能實(shí)現(xiàn)這個(gè)效果懂鸵,但是你們不覺(jué)得一串串html的代碼硬編碼在Android項(xiàng)目里很難看么偏螺!而且經(jīng)過(guò)我對(duì) Html.fromHtml( ) 的源碼的研究發(fā)現(xiàn),這個(gè)方法并沒(méi)有什么神秘之處(能夠DuangDuang的就給文字加特技匆光,呸! 加樣式)套像。
mSpannableStringBuilder = new SpannableStringBuilder();
if (end == start) {
mSpannableStringBuilder.removeSpan(obj[i]);
} else {
mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH);
}
上面是截取了部分Html.fromHtml( ) 方法調(diào)用的源碼。細(xì)心的小伙伴們肯定發(fā)現(xiàn)了终息,這里面出現(xiàn)了個(gè)SpannableStringBuilder()夺巩。所以一切真相大白了贞让,原來(lái)該方法將html解析之后通過(guò)SpannableStringBuilder來(lái)給他添加樣式×看到這的小伙伴們是不是學(xué)會(huì)用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類(lèi)似,簡(jiǎn)單舉個(gè)例子征绎,不做過(guò)多的解釋蹲姐。
3.SpannableStringBuilder
本章的主角,SpannableString的好基友人柿。
class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable,
Appendable, GraphicsOperations{}
//這里主要注意CharSequence和Spannable
//繼承自Spannable柴墩,賦予了它給文本設(shè)定樣式的基礎(chǔ)功能
//實(shí)現(xiàn)接口CharSequence則代表了他能在很多地方使用,比如TextView的setText方法的參數(shù)就是CharSequence對(duì)象
下面來(lái)看主要的兩個(gè)方法
public SpannableStringBuilder append(CharSequence text) {}
//將文本添加到SpannableStringBuilder中凫岖,和StringBuilder的append方法功能類(lèi)似
public void setSpan(Object what, int start, int end, int flags) {}
用于設(shè)置樣式的核心方法江咳。參數(shù):
- what
各種Span,不同的Span對(duì)應(yīng)不同的樣式哥放,具體有如下:
- ForegroundColorSpan : 設(shè)置文本前景色(文本顏色)
- BackgroundColorSpan : 設(shè)置背景顏色
- AbsoluteSizeSpan : 設(shè)置絕對(duì)的文字大小歼指,px單位
- ClickableSpan : 為文字添加點(diǎn)擊事件(類(lèi)似于微信朋友圈評(píng)論列表中用戶(hù)的昵稱(chēng)點(diǎn)擊事件就可以用這個(gè)實(shí)現(xiàn))
- DynamicDrawableSpan :
- ImageSpan : 文文本添加圖片
- RelativeSizeSpan : 設(shè)置相對(duì)文字大小,為倍數(shù)甥雕,相對(duì)于其他文字的大小
- StrikethroughSpan : 添加刪除線(xiàn)
- SubscriptSpan : 設(shè)置下標(biāo)文字
- SuperscriptSpan : 設(shè)置上標(biāo)文字
- URLSpan : 文字設(shè)定超鏈接
- UnderlineSpan : 設(shè)置下劃線(xiàn)
- start
樣式生效的開(kāi)始位置踩身,包括該位置
3)end
樣式結(jié)束的位置,不包括該位置社露,所以設(shè)定一串文字中前3個(gè)文字的樣式時(shí)start:0,end:3挟阻。而不是end:2 - flags
這幾個(gè)參數(shù)中最難懂最麻煩最難搞的一個(gè)參數(shù)。
主要有以下四個(gè)值:
- Spannable.SPAN_EXCLUSIVE_INCLUSIVE:在 Span前面輸入的字符不應(yīng)用 span 的效果峭弟,在后面輸入的字符應(yīng)用Span效果附鸽。
- Spannable.SPAN_INCLUSIVE_EXCLUSIVE:在 Span前面輸入的字符應(yīng)用 span 的效果,在后面輸入的字符不應(yīng)用Span效果瞒瘸。
- Spannable.SPAN_INCUJSIVE_INCLUSIVE:在 Span前后輸入的字符都應(yīng)用 span 的效果坷备。
-
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:在 Span前后輸入的字符前后都不應(yīng)用 span 的效果。
看得小伙伴們一頭霧水對(duì)吧情臭,前前后后用不用的省撑,啥玩意?
接下來(lái)我上兩張圖讓大家看懂這四個(gè)flag的區(qū)別
這是對(duì)同一段文字設(shè)置相同的span俯在,區(qū)別在于flag的不同丁侄,4個(gè)的效果是不是一毛一樣呢?
這張圖片中的 “zz” 是在EditText中輸入進(jìn)去的朝巫,小伙伴們結(jié)合上面對(duì)4個(gè)flag的介紹鸿摇,是不是能理解了呢?
//部分代碼
final String baseString="這是開(kāi)始的文字";
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.激動(dòng)人心的實(shí)戰(zhàn)時(shí)刻
ForegroundColorSpan的使用:
SpannableStringBuilder sb=new SpannableStringBuilder();
sb.append("紅色綠色藍(lán)色");
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);
//替換掉了前兩個(gè)文字劈猿,所以添加的圖片占用兩個(gè)文字的寬度
tv.setText(sb);
效果:
說(shuō)好的大家一起做文字的拙吉,你卻偷偷整容成圖片了潮孽,哼!
ClickableSpan:
SpannableStringBuilder sb=new SpannableStringBuilder();
sb.append("我們中有兩個(gè)文字可以點(diǎn)擊哦");
ClickableSpan span=new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(MainActivity.this,"你點(diǎn)擊了我",Toast.LENGTH_LONG).show();
}
};
sb.setSpan(span,0,2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(sb);
//設(shè)置了點(diǎn)擊事件后請(qǐng)加上這句筷黔,不然點(diǎn)擊事件不起作用
tv.setMovementMethod(LinkMovementMethod.getInstance());
效果:
別忘了這一句:tv.setMovementMethod(LinkMovementMethod.getInstance());
很重要往史。
另外給文字設(shè)置點(diǎn)擊事件之后會(huì)自動(dòng)給文字加上下劃線(xiàn),可以使用如下方式去除這個(gè)默認(rèn)的下劃線(xiàn):
//自定義類(lèi)繼承自ClickableSpan佛舱。用該類(lèi)來(lái)代替使用
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使用例子,其他幾個(gè)Span的適用方法還請(qǐng)小伙伴們自己探索请祖,畢竟自己動(dòng)手學(xué)的快嘛(我才不會(huì)說(shuō)是我自己懶??6┩帷)
另外小伙伴們是不是覺(jué)得new出一個(gè)又一個(gè)的span很麻煩呢,而且手動(dòng)計(jì)算start肆捕,end很麻煩呢刷晋?下面給大家推薦一個(gè)簡(jiǎn)單的輔助類(lèi)。
好了慎陵,以上都是廣告時(shí)間眼虱,下面進(jìn)入正文:
歡迎小伙伴使用我寫(xiě)的一個(gè)輔助工具類(lèi),gayhub地址:https://github.com/zYinux/SpecialString席纽。
使用了該庫(kù)之后設(shè)置樣式只需要:
//構(gòu)建SpecialStyle 用來(lái)設(shè)置樣式的核心類(lèi)
SpecialStyle style=new SpecialStyle();
SpecialStringBuilder sb=new SpecialStringBuilder();
//設(shè)置文本顏色為黑色捏悬。第二個(gè)參數(shù)save的意思是代表該樣式是否應(yīng)用到下一段文字,如果不傳則為true
style.setColor(Color.BLACK,false);
//為文字設(shè)置樣式
sb.append("售價(jià):",style);
style.setColor(Color.RED,false);
sb.append("¥99.99 ",style);
//設(shè)置顏色背景和點(diǎn)擊事件樣式
//點(diǎn)擊事件默認(rèn)為不應(yīng)用于下一段文字
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,"開(kāi)始搶購(gòu)",Toast.LENGTH_SHORT).show();
}
});
sb.append("立即搶購(gòu)",style);
//為T(mén)extView設(shè)置剛剛構(gòu)建的文本
tv.setText(sb.getCharSequence());
//如果為文字添加了點(diǎn)擊事件润梯,請(qǐng)?zhí)砑舆@一句过牙,否則點(diǎn)擊事件不生效
tv.setMovementMethod(LinkMovementMethod.getInstance());
是不是簡(jiǎn)單了很多了呢?終于不用去理會(huì)那些煩人的start仆救,end抒和,flag了矫渔。具體使用方法請(qǐng)大家轉(zhuǎn)到GitHub查看彤蔽,方便的話(huà)歡迎小伙伴給個(gè)star,謝謝啦庙洼。
5.瞎逼逼時(shí)間
小伙伴們好顿痪!
我叫 zYinux ,取這個(gè)網(wǎng)名是為了致敬IT界的大佬的項(xiàng)目Linux油够∫舷可惜目前我還是一個(gè)剛?cè)腴T(mén)的菜鳥(niǎo),希望能通過(guò)自己的努力攀爬到更高的境界石咬。這是我寫(xiě)的第二篇博客揩悄,上一篇已是1年前了,接下來(lái)會(huì)努力一個(gè)月出一篇博客鬼悠。文筆不好望大家見(jiàn)諒删性,希望看到這里的小伙伴已經(jīng)學(xué)會(huì)了上面的知識(shí)亏娜,如果小伙伴發(fā)現(xiàn)了教程中有錯(cuò)誤和遺漏之處,歡迎聯(lián)系我指正蹬挺。
QQ交流群:589184413