天天看點

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

上一篇部落格講了怎麼用SpannableString實作表情、文字混合顯示的EditText和TextView。

其實顯示表情隻是SpannableString的一個小功能,它的強大之處今天将完全展示出來。利用SpannableString,我們可以對一個TextView中的每一個字元做各種各樣的變化。

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

前陣子電腦中病毒了,是一個流氓軟體,每天定時在背景安裝程式。我也不懂電腦就沒管它。

直到有一天它自己安裝了個360,然後360掃描出了這個流氓軟體,把它解除安裝了。。。

首先來看一下效果圖

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

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

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

1)預設樣式

不解釋。。。就是啥都不設定。

2)自定義字型

SpannableString ss1 = new SpannableString(txCustomTypeface.getText());
ss1.setSpan(new TypefaceSpan("serif"), , 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(, true), , 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(f), , txRelativeSize.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txRelativeSize.setText(ss3);
           

這個和上面類似,表示字型大小是預設大小的幾倍。

5)字型前景色

SpannableString ss4 = new SpannableString(txForegroundColor.getText());
ss4.setSpan(new ForegroundColorSpan(Color.BLUE), , 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), , txBackgroundColor.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txBackgroundColor.setText(ss5);
           

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

7)粗斜體

SpannableString ss6 = new SpannableString(txBordAndItalic.getText());
ss6.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), , 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(), , txUnderLine.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txUnderLine.setText(ss7);
           

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

9)删除線

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

不解釋了。

10)上标、下标

SpannableString ss9 = new SpannableString(txSubSuperScript.getText());
ss9.setSpan(new SuperscriptSpan(), , , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ss9.setSpan(new SubscriptSpan(), , , 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"), , 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]"), , 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"), , 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"), , 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"), , 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"), , 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(, Color.RED), , txBullte.getText().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
txBullte.setText(ss16);
           

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

13)橫向拉伸

SpannableString ss17 = new SpannableString(txScaleX.getText());
ss17.setSpan(new ScaleXSpan(), , 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, , csl1, csl1), , 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,沒想到這麼強大吧!我們平時用的隻是它最最簡答的功能。

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

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