前言: 一件事無論太晚或者太早,都不會阻止你成爲你想要成爲的那個人。 ——《本傑明巴頓奇事》
一、概述
SpannableString和String一樣都是一種字符串類型,SpannableString源碼中的解釋是:這類內容的文本是不變的,但是標記對象可以被附加和分離。也就是說,可以改變文本中的部分字符串,打造豐富多彩的文本顯示效果。
一般項目中總會需要有在同一個文本中顯示字體不同顏色,不同大小等效果,雖然可以在XML文件中設置多個TextView可以實現效果,但是在佈局優化的角度來說是不合適的,我們可以通過SpannableString來實現部分文本的顏色改變,不同字體大小,斜體,下劃線等功能。
二、SpannableString的使用
2.1 改變前景顏色(字體顏色)
在一個TextView中改變部分文字的顏色,需要在SpannableString設置前景顏色ForegroundColorSpan中添加你需要改變的顏色。
- ForegroundColorSpan: 設置文本前景色,即文本顏色,在構造方法中傳入需要改變的顏色即可。
//構造字符串
SpannableString spannableString = new SpannableString("改變部分文字顏色");
//構造前景顏色Span
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.parseColor("#2196F3"));
//給字符串設置樣式
spannableString.setSpan(fcs, 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
上面例子中,我們在第六到第八個字符串中改變了前景色,效果如下:
這裏解釋一下設置樣式setSpan(Object what, int start, int end, int flags)
這個方法:
- Object what: 各種Span,不同的Span對應不同的樣式,例如:URLSpan : 文字設定超鏈接;ForegroundColorSpan : 設置文本前景色(文本顏色);
- int start: 樣式生效的起始位置(起始下標),包括該位置;
- int end: 樣式生效的結束位置(終止下標),不包括該位置,比如:改變前三個文字樣式,start:0,end:3,表示下標爲0,1,2的文字會改變;
- int flags: Span樣式,它有四種參數,如下:
- Spannable.SPAN_EXCLUSIVE_INCLUSIVE:在Sapn前面輸入的字符不應用span的效果,在Sapn後面輸入的字符應用span的效果;
- Spannable.SPAN_INCLUSIVE_EXCLUSIVE:在Sapn前面輸入的字符應用span的效果,在Sapn後面輸入的字符不應用span的效果;
- Spannable.SPAN_INCUJSIVE_INCLUSIVE:在Sapn前後輸入的字符都應用span的效果;
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:在Sapn前後輸入的字符都不應用span的效果。
我們來演示一下效果,分別設置4個不同的EditText,爲每個EditText的Span設置不同flags(效果如下左圖),然後分別在顏色字體“文字”的左右分別加入“ss”,ss是否跟隨Span的樣式來改變顏色(如下右圖):
在Span樣式文字前後分別加入ss字符,ss的樣式是否和文字樣式一起改變。效果對比如上圖,一目瞭然了。
2.2 改變背景顏色
BackgroundColorSpan爲設置背景色Span,用法與上面的例子類似:
- BackgroundColorSpan: 設置文本背景顏色,在構造方法中傳入需要改變的顏色即可。
//構造字符串
SpannableString spannableString = new SpannableString("設置文字的背景色爲紅色");
//構造背景顏色Span
BackgroundColorSpan bcs = new BackgroundColorSpan(Color.RED);
//設置樣式給spannableString
spannableString.setSpan(bcs, 5, 8, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
我們將“背景色”文字的背景改爲紅色,改變效果如下:
2.3 設置字體大小
同樣我們可以設置同一文本的不同字體大小,RelativeSizeSpan,AbsoluteSizeSpan
- RelativeSizeSpan: 設置相對文字大小,爲倍數,相對於原文字的大小;
- AbsoluteSizeSpan: 爲設置絕對文字的大小,px爲單位,也可以設置爲dp。
//相對大小
SpannableString spannableString = new SpannableString("設置文字的大小:相對RelativeSizeSpan");
//構造相對尺寸Span, 參數:float proportion 表示相對放大縮小的倍數
RelativeSizeSpan rss = new RelativeSizeSpan(2f);//放大爲兩倍
//設置樣式給spannableString
spannableString.setSpan(rss, 8, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
//絕對大小
SpannableString spannableString2 = new SpannableString("設置文字的大小:絕對AbsoluteSizeSpan");
//參數:int size 表示尺寸大小,默認文px; boolean dip表示是否爲dp
AbsoluteSizeSpan ass = new AbsoluteSizeSpan(20, true);//大小爲20dp
spannableString2.setSpan(ass, 8, spannableString2.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView2.setText(spannableString2);
我們將相對文字設置爲原來的兩倍大小,將絕對文字設置爲20dp,效果如下:
2.4 設置字體風格
- StyleSpan: 設置文字風格,如果加粗,斜體等風格。Typeface.BOLD:粗體、Typeface.ITALIC:斜體、Typeface.BOLD_ITALIC:斜體加粗。
//構造字符串
SpannableString spannableString = new SpannableString("爲文字設置粗體和斜體風格");
//構造字體風格
StyleSpan boldSpan = new StyleSpan(Typeface.BOLD);//粗體
StyleSpan italtcSpan = new StyleSpan(Typeface.ITALIC);//斜體
//設置樣式給spannableString
spannableString.setSpan(boldSpan, 5, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableString.setSpan(italtcSpan, 8, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
我們設置了文字加粗和斜體,效果如下:
2.5 設置下劃線和刪除線
- UnderlineSpan : 設置下劃線;
- StrikethroughSpan : 設置刪除線。
//下劃線
SpannableString spannableString = new SpannableString("爲文字設置下劃線");
//構造下劃線Span
UnderlineSpan us = new UnderlineSpan();
//設置樣式給spannableString
spannableString.setSpan(us, 5, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
//刪除線
SpannableString spannableString2 = new SpannableString("爲文字設置刪除線");
//構造刪除線Span
StrikethroughSpan ss = new StrikethroughSpan();
spannableString2.setSpan(ss, 5, spannableString2.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView2.setText(spannableString2);
我們爲文字添加了下劃線和刪除線,效果如下:
2.6 設置文字上標和下標
- SuperscriptSpan : 設置文字上標;
- SubscriptSpan : 設置文字下標。
//文字上標
SpannableString spannableString = new SpannableString("爲文字設置上標");
//上標Span
SuperscriptSpan supersSpan = new SuperscriptSpan();
//設置樣式給spannableString
spannableString.setSpan(supersSpan, 5, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
//文字下標
SpannableString spannableString2 = new SpannableString("爲文字設置下標");
//下標Span
SubscriptSpan subsSpan = new SubscriptSpan();
spannableString2.setSpan(subsSpan, 5, spannableString2.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView2.setText(spannableString2);
我們設置了文字上標和文字下標,效果如下:
2.7 設置圖片
- ImageSpan: 設置圖片。
//下劃線
SpannableString spannableString = new SpannableString("爲文字設置圖片");
//圖片Span
ImageSpan is = new ImageSpan(this, R.mipmap.ic_head);
//設置樣式給spannableString
spannableString.setSpan(is, 5, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//設置字符串
textView.setText(spannableString);
將上面的“圖片”替換爲圖片,可用於表情替換文字。效果如下:
2.8 設置可點擊文本
爲文字添加點擊事件,類似朋友圈點擊用戶暱稱實現跳轉可以用這個實現。
- ClickableSpan: 設置可以點擊文本,ClickableSpan爲抽象類,需要自定義類實現其中的方法。
//響應文本點擊
SpannableString spannableString = new SpannableString("設置可點擊文本:點擊這裏");
//圖片Span
MyClickableSpan myClickableSpan = new MyClickableSpan(this);
//設置樣式給spannableString
spannableString.setSpan(myClickableSpan, 8, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//必須設置這個方法,否則點擊沒有響應
textView.setMovementMethod(LinkMovementMethod.getInstance());
//設置字符串
textView.setText(spannableString);
ClickableSpan
是抽象類,我們需要創建一個自定義類MyClickableSpan
實現ClickableSpan
中的onClick()
方法,並在該方法中實現你需要的點擊事件邏輯。
public class MyClickableSpan extends ClickableSpan {
private Context mContext;
public MyClickableSpan(Context context) {
this.mContext = context;
}
@Override
public void onClick(@NonNull View widget) {
Toast.makeText(mContext, "響應點擊事件:https://blog.csdn.net/m0_37796683", Toast.LENGTH_SHORT).show();
}
}
注意:如果要響應點擊事件則需要實現setMovementMethod()
方法,它是處理光標,文本滾動和選擇等功能,這個類似TextView設置點擊事件setOnClickListener()
一樣。
將“點擊這裏”設置爲可點擊文本,點擊後響應MyClickableSpan
的onClick()
事件,效果如下:
2.9 設置超鏈接文本
- URLSpan : 設置超文本鏈接,上一個例子已經實現了超鏈接的效果,繼承ClickableSpan重寫onClick()方法就可以了,URLSpan也是這樣實現的,只不過使用內部瀏覽器打開鏈接。
SpannableString spannableString = new SpannableString("爲文字設置超鏈接");
//超鏈接Span
URLSpan urlSpan = new URLSpan("https://www.baidu.com");
//設置樣式給spannableString
spannableString.setSpan(urlSpan, 5, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//必須設置這個方法,否則點擊沒有響應
textView.setMovementMethod(LinkMovementMethod.getInstance());
//設置字符串
textView.setText(spannableString);
我們爲"超鏈接"三個文字設置鏈接,效果如下:
URLSpan
的onClick()
方法源碼:
@Override
public void onClick(View widget) {
Uri uri = Uri.parse(getURL());
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
}
}
2.10 SpannableStringBuilder
- SpannableStringBuilder: 實現各種風格效果的SpannableString拼接,類似StringBuilder,實現字符串的拼接。
//文本
SpannableString str1 = new SpannableString("一件事無論太晚或者太早,");
SpannableString str2 = new SpannableString("都不會阻止你成爲你想要成爲的那個人。");
SpannableString str3 = new SpannableString("——《本傑明巴頓奇事》");
//文字顏色
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.BLUE);
str1.setSpan(foregroundColorSpan, 0, 3, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//背景色
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.YELLOW);
str2.setSpan(backgroundColorSpan, 8, str2.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//斜體和下劃線
StyleSpan styleSpan = new StyleSpan(Typeface.ITALIC);
UnderlineSpan underlineSpan = new UnderlineSpan();
str3.setSpan(styleSpan, 3, str3.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
str3.setSpan(underlineSpan, 3, str3.length() - 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
//拼接SpannableString
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(str1);
ssb.append(str2);
ssb.append(str3);
textView.setText(ssb);
我們綜合使用了一部分效果,通過SpannableStringBuilder拼接起來,效果如下:
至此,本文結束!