Android SpannableString和SpannableStringBuilder教程
一.導引
1.適用物件
-
沒有接觸過SpannableString的人
-
聽過但是不熟悉不瞭解SpannableString的人。
2.教程結構
- 簡介
- SpannableString
- SpannableStringBuilder
- 實戰部分
- 總結和感想(作者瞎逼逼時間)
二.正文
1.簡介
SpannableString和SpannableStringBuilder的關係類似於String和StringBuilder。前者不可變,後者可變。所以兩者的使用方法基本相同。
功能在於給一串普通的字串加上顏色,大小背景等樣式和特殊事件(點選事件)。下面先上一個例子

image
這個例子很普通,小夥伴們一看可能會覺得這不就是幾個TextView嗎?
沒錯,這就是TextView。但不是幾個,而是一個,只用一個TextView顯示出這串花花綠綠的文字是不是很:ox:的感覺呢?
這個時候可能有小夥伴會說:“一個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很有用了呢!:grin:
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的區別
image
這是對同一段文字設定相同的span,區別在於flag的不同,4個的效果是不是一毛一樣呢?
image
這張圖片中的 “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);
效果:

image
花花綠綠的最好看了☺
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);
效果:

image
說好的大家一起做文字的,你卻偷偷整容成圖片了,哼!
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());
效果:

image
別忘了這一句: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的適用方法還請小夥伴們自己探索,畢竟自己動手學的快嘛(我才不會說是我自己懶:confused:!)
另外小夥伴們是不是覺得new出一個又一個的span很麻煩呢,而且手動計算start,end很麻煩呢?下面給大家推薦一個簡單的輔助類。
好了,以上都是廣告時間,下面進入正文:
歡迎小夥伴使用我寫的一個輔助工具類,gayhub地址: ofollow,noindex">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