Android千變萬化TextView(SpannableString全解析)

上一篇博客講了怎麼用SpannableString實現表情、文字混合顯示的EditText和TextView。
其實顯示錶情只是SpannableString的一個小功能,它的強大之處今天將完全展示出來。利用SpannableString,我們可以對一個TextView中的每一個字符做各種各樣的變化。

老規矩,在本期節目開始之前,先來一個搞笑段子:

前陣子電腦中病毒了,是一個流氓軟件,每天定時在後檯安裝程序。我也不懂電腦就沒管它。
直到有一天它自己安裝了個360,然後360掃描出了這個流氓軟件,把它卸載了。。。

首先來看一下效果圖
這裏寫圖片描述

這裏總共20行,每一行都是TextView(除了最後一個),只是SpannableString設置了不同span。

下面來一個一個解釋每一種樣式的實現方式:

1)默認樣式
不解釋。。。就是啥都不設置。

2)自定義字體

SpannableString ss1 = new SpannableString(txCustomTypeface.getText());
ss1.setSpan(new TypefaceSpan("serif"), 0, txCustomTypeface.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txCustomTypeface.setText(ss1);

自定義樣式對應的Span爲TypefaceSpan,它的構造函數傳的是字體樣式,總共有5種:
default,default-bold,monospace,serif,sans-serif

3)字體絕對大小

SpannableString ss2 = new SpannableString(txAbsoluteSize.getText());
ss2.setSpan(new AbsoluteSizeSpan(16, true), 0, txAbsoluteSize.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txAbsoluteSize.setText(ss2);

它對應的Span是AbsoluteSizeSpan,構造函數第一個參數是字體大小,第二個參數表示是否轉換爲dp。
比如第一個參數是20,第二個參數如果爲true,則表示20dp, 否則表示20px。

4)字體相對大小

SpannableString ss3 = new SpannableString(txRelativeSize.getText());
ss3.setSpan(new RelativeSizeSpan(1.5f), 0, txRelativeSize.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txRelativeSize.setText(ss3);

這個和上面類似,表示字體大小是默認大小的幾倍。

5)字體前景色

SpannableString ss4 = new SpannableString(txForegroundColor.getText());
ss4.setSpan(new ForegroundColorSpan(Color.BLUE), 0, txForegroundColor.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txForegroundColor.setText(ss4);

它對應的Span是ForegroundColorSpan,參數傳顏色值,一目瞭然。

6)字體背景色

SpannableString ss5 = new SpannableString(txBackgroundColor.getText());
ss5.setSpan(new BackgroundColorSpan(Color.LTGRAY), 0, txBackgroundColor.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txBackgroundColor.setText(ss5);

前景色明白了,背景色就不用解釋了吧。

7)粗斜體

SpannableString ss6 = new SpannableString(txBordAndItalic.getText());
ss6.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, txBordAndItalic.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txBordAndItalic.setText(ss6);

它對應的是StyleSpan,參數是樣式,總共有4種:
Typeface.NORMAL:普通
Typeface.BORD:粗體
Typeface.ITALIC:斜體
Typeface.BORD_ITALIC:粗斜體

8)下劃線

SpannableString ss7 = new SpannableString(txUnderLine.getText());
ss7.setSpan(new UnderlineSpan(), 0, txUnderLine.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txUnderLine.setText(ss7);

看了這麼多,是不是發現用法都一樣。。。只是Span對象不一樣而已。

9)刪除線

SpannableString ss8 = new SpannableString(txDeleteLine.getText());
ss8.setSpan(new StrikethroughSpan(), 0, txDeleteLine.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txDeleteLine.setText(ss8);

不解釋了。

10)上標、下標

SpannableString ss9 = new SpannableString(txSubSuperScript.getText());
ss9.setSpan(new SuperscriptSpan(), 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss9.setSpan(new SubscriptSpan(), 5, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txSubSuperScript.setText(ss9);

這裏需要注意,這裏兩個span對應的是上標和下標的字符。

11)超鏈接形式

這裏需要重點解釋下,超鏈接對應的Span叫做URLSpan,它有6中表現形式:
電話、郵件、網址、短信、彩信、地圖
它們都是URLSpan,只是參數的格式不一樣。
電話:”tel:02512345678”
郵件:”mailto:[email protected]
網址:”http://www.baidu.com
短信:”sms:02512345678”
彩信:”mms:02512345678”
地圖:”geo:30.123456,-50.024456”

不同的格式有什麼用呢?答案是這樣的。
指定URLSpan的TextView是有點擊效果的,比如:
指定電話URLSpan,點擊會自動跳轉到電話App,並且攜帶的就是URL中的號碼。
其它的類似,都會跳轉對應的App。

這個明白了,下面6段代碼就很簡單啦!

SpannableString ss10 = new SpannableString(txTelUrl.getText());
ss10.setSpan(new URLSpan("tel:02512345678"), 0, txTelUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txTelUrl.setText(ss10);
txTelUrl.setMovementMethod(LinkMovementMethod.getInstance());

SpannableString ss11 = new SpannableString(txMailUrl.getText());
ss11.setSpan(new URLSpan("mailto:[email protected]"), 0, txMailUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txMailUrl.setText(ss11);
txMailUrl.setMovementMethod(LinkMovementMethod.getInstance());

SpannableString ss12 = new SpannableString(txWebUrl.getText());
ss12.setSpan(new URLSpan("http://www.baidu.com"), 0, txWebUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txWebUrl.setText(ss12);
txWebUrl.setMovementMethod(LinkMovementMethod.getInstance());

SpannableString ss13 = new SpannableString(txSmsUrl.getText());
ss13.setSpan(new URLSpan("sms:02512345678"), 0, txSmsUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txSmsUrl.setText(ss13);
txSmsUrl.setMovementMethod(LinkMovementMethod.getInstance());

SpannableString ss14 = new SpannableString(txMmsUrl.getText());
ss14.setSpan(new URLSpan("mms:02512345678"), 0, txMmsUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txMmsUrl.setText(ss14);
txMmsUrl.setMovementMethod(LinkMovementMethod.getInstance());

SpannableString ss15 = new SpannableString(txGeoUrl.getText());
ss15.setSpan(new URLSpan("geo:30.123456,-50.024456"), 0, txGeoUrl.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txGeoUrl.setText(ss15);
txGeoUrl.setMovementMethod(LinkMovementMethod.getInstance());

但是別急,你有沒有發現這6段代碼跟之前的有一點不一樣?

是的,這6段代碼每一段後面都加了一句:textView.setMovementMethod(LinkMovementMethod.getInstance());
這是必須要加的。不加是不能激活鏈接的。

12)項目符號

SpannableString ss16 = new SpannableString(txBullte.getText());
ss16.setSpan(new BulletSpan(0, Color.RED), 0, txBullte.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txBullte.setText(ss16);

它對應的是BulletSpan,第一個參數表示的是項目符號的寬度,第二個參數是項目符號的顏色。

13)橫向拉伸

SpannableString ss17 = new SpannableString(txScaleX.getText());
ss17.setSpan(new ScaleXSpan(2), 0, txScaleX.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txScaleX.setText(ss17);

它對應的是ScaleXSpan,參數就是縮放的倍數。

你或許會想有ScaleX,肯定有ScaleY吧?
很遺憾,我沒找到。。。

14)綜合運用

ColorStateList csl1 = null;
try{
    XmlResourceParser xrp = getResources().getXml(R.drawable.text_csl);
    csl1 = ColorStateList.createFromXml(getResources(), xrp);
} catch (XmlPullParserException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

//依次包括字體名稱,字體大小,字體樣式,字體顏色,鏈接顏色
SpannableString ss18 = new SpannableString(txUseAll.getText());
ss18.setSpan(new TextAppearanceSpan("monospace", Typeface.BOLD, 50, csl1, csl1), 0, txUseAll.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txUseAll.setText(ss18);

這個Span和前面的不一樣,它比較強大,可以一次性設置多項屬性,在代碼中也註釋了,分別是:
字體名稱,字體大小,字體樣式,字體顏色,鏈接顏色。

這裏我偷懶,字體顏色和鏈接顏色就用了同一個。

15)ColorStateList

最後來講一下ColorStateList吧。它是幹什麼用的呢?先不急。

大家有沒有遇到過這種需求:
寫一個Button,正常狀態背景顏色是白色,字體顏色是黑色;
手指按下時反過來,背景顏色是黑色,字體顏色是白色。

背景顏色很簡單,用一個selector,然後button.setBackground(R.drawable.selector);
那字體顏色怎麼辦呢?沒辦法用selector,這時候就用到了ColorStateList。

看名字就知道,它是表示顏色和狀態的一個集合。
再看它的創建方法:

XmlResourceParser xrp = getResources().getXml(R.drawable.text_csl);
csl1 = ColorStateList.createFromXml(getResources(), xrp);

哈哈,原來,它就是selector,只是穿了個馬甲而已。。。

代碼:

ColorStateList csl2 = null;
try {
    XmlResourceParser xrp = getResources().getXml(R.drawable.button_text);
    csl2 = ColorStateList.createFromXml(getResources(), xrp);
} catch (XmlPullParserException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
button.setTextColor(csl2);

好了,全部講完了,是不是覺得並不複雜,用法幾乎是一毛一樣的,只是Span對象不同而已。
這就是Android爲我們封裝的TextView,沒想到這麼強大吧!我們平時用的只是它最最簡答的功能。

現在堅持有空就寫寫博客,敲一遍記錄一遍,自己的記憶就更深刻,掌握的就更牢固。同樣也能幫助到一些其它正在學習的人。我每天也在從別人那裏學習到新的技術,互幫互助。

本期節目就到這裏,感謝大家的收看,我們下期再見~

發佈了40 篇原創文章 · 獲贊 88 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章