Android設置TextView樣式SpannableString教程
前言
最近沒什么比較好的思路,所以基本是想到什么寫什么。很多人有碰到過這樣的需求,展示一段文字,但是這段文字中間的幾個字顏色不同,比如這樣:
展示一段 這幾個字顏色不同\color{red}{這幾個字顏色不同}這幾個字顏色不同 的文字
只是其中有一段要換文字的樣式而已,其它的顯示正常。有的人實現(xiàn)這個功能就用3個TextView去實現(xiàn)的,其實這是不對的,
有一些開發(fā)經(jīng)驗的就知道有個類是SpannableString,它能實現(xiàn)這個功能。
SpannableString的使用
為什么它能實現(xiàn)這個功能呢?其實你setTextView最終還是繪制出來,比如大家都知道Canvas是能繪制文字的,如果我用Canvas去繪制文字的話,我就很輕易能實現(xiàn)各種效果,包括上面的一段文字變色。其實SpannableString的效果就相當于Canvas去繪制的效果一樣。
而spannableStringBuilder相對于SpannableString而言是多了拼接的效果,他們都一樣,所以我這里就以spannableStringBuilder來說,如果我要使用spannableStringBuilder去實現(xiàn)上面的效果,可以這樣寫
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(“展示一段這幾個字顏色不同的文字”); ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED); spannableStringBuilder.setSpan(foregroundColorSpan, 4, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textview.setText(spannableStringBuilder);
這樣就能實現(xiàn)上面的效果了,我們可以簡單看看ForegroundColorSpan,它有個updateDrawState方法
/**
* Updates the color of the TextPaint to the foreground color.
*/
@Override
public void updateDrawState(@NonNull TextPaint textPaint) {
textPaint.setColor(mColor);
}
TextPaint繼承Paint,能看出這是一個設置畫筆的動作。而spannableStringBuilder的setSpan方法的第一個參數(shù)就是指Span,那讓我們來看看系統(tǒng)提供了哪些常見的Span(我這里就列舉幾個常用的)
- ForegroundColorSpan:文本顏色
- BackgroundColorSpan:背景顏色
- AbsoluteSizeSpan:字體的大?。ń^對值)
- RelativeSizeSpan:字體的大?。ㄏ鄬χ?,xx倍)
- StyleSpan:字體的風格
- UnderlineSpan:下劃線
- StrikethroughSpan:刪除線
除了這些之外還有RasterizerSpan、ImageSpan、TypefaceSpan等等,感興趣的可以去看官方文檔,我這就不介紹這么多了。
然后我們看setSpan的最后一個參數(shù)flags,一共有4種類型:
- SPAN_EXCLUSIVE_EXCLUSIVE:包括前面,包括后面
- SPAN_EXCLUSIVE_INCLUSIVE:包括前面,不包括后面
- SPAN_INCLUSIVE_EXCLUSIVE:不包括前面,包括后面
- SPAN_INCLUSIVE_INCLUSIVE:不包括前面,不包括后面
這是什么意思呢?看得出它的命名有兩個單詞_EXCLUSIVE_EXCLUSIVE這樣的,第一個表示影響范圍是前面,第二個表示影響范圍是后面。EXCLUSIVE表示包括,INCLUSIVE表示不包括。
假如我這句話“123456”,我設置2種樣式,123用ForegroundColorSpan設置字體為紅色,456用BackgroundColorSpan設置背景為紅色。假如123使用SPAN_EXCLUSIVE_EXCLUSIVE,456使用SPAN_INCLUSIVE_INCLUSIVE,那最終效果是123字體是紅色,456字體和背景都是紅色。
封裝SpannableString
簡單的介紹了SpannableString的作用和調(diào)用方式,我們來看看具體怎么使用,如果你按照上面的代碼,每設置一個文字效果,都要寫這么一串代碼,那最終看起來會很臃腫
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append(“展示一段這幾個字顏色不同的文字”); ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED); spannableStringBuilder.setSpan(foregroundColorSpan, 4, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textview.setText(spannableStringBuilder);
所以我們可以封裝一下(把自己會用上的效果先整合起來)
public class SpanStringUtils {
private Context context;
private SpannableStringBuilder spannableStringBuilder;
private int lp = 0;
private int rp = 0;
private List<Span> list = new ArrayList<>();
public SpanStringUtils(Context context) {
this.context = context;
spannableStringBuilder = new SpannableStringBuilder();
}
public SpanStringUtils append(Span span) {
list.add(span);
return this;
}
public CharSequence create() {
if (list == null || list.isEmpty()) {
return null;
}
for (int i = 0; i < list.size(); i++) {
Span span = list.get(i);
createSpan(span);
}
return spannableStringBuilder;
}
private void createSpan(Span span) {
if (span != null) {
String str = span.textRId == -1 ? span.text : context.getString(span.textRId);
rp = lp + str.length();
spannableStringBuilder.append(str);
if (span.spannable != null) {
spannableStringBuilder.setSpan(span.spannable, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.textColor != -1) {
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(context.getResources().getColor(span.textColor));
spannableStringBuilder.setSpan(foregroundColorSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.backgroundColor != -1) {
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(context.getResources().getColor(span.backgroundColor));
spannableStringBuilder.setSpan(backgroundColorSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.relativeSize > 0) {
RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(span.relativeSize);
spannableStringBuilder.setSpan(relativeSizeSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.xSpan > 0) {
ScaleXSpan scaleXSpan = new ScaleXSpan(span.xSpan);
spannableStringBuilder.setSpan(scaleXSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.style != -1) {
StyleSpan styleSpan = new StyleSpan(span.style);
spannableStringBuilder.setSpan(styleSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.isUnderline) {
UnderlineSpan underlineSpan = new UnderlineSpan();
spannableStringBuilder.setSpan(underlineSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (span.isStrikethrough) {
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
spannableStringBuilder.setSpan(strikethroughSpan, lp, rp, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
lp = rp;
}
}
public static class Span {
private String text;
private int textRId = -1;
private int textColor = -1;
private int backgroundColor = -1;
private float relativeSize;
private float xSpan;
private int style = -1;
private boolean isUnderline;
private boolean isStrikethrough;
private ParcelableSpan spannable;
public Span setText(String text) {
this.text = text;
return this;
}
public Span setText(int rId) {
this.textRId = rId;
return this;
}
public Span setTextColor(int textColor) {
this.textColor = textColor;
return this;
}
public Span setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
return this;
}
public Span setRelativeSize(float relativeSize) {
this.relativeSize = relativeSize;
return this;
}
public Span setxSpan(float xSpan) {
this.xSpan = xSpan;
return this;
}
public Span setStyle(int style) {
this.style = style;
return this;
}
public Span setUnderline(boolean underline) {
isUnderline = underline;
return this;
}
public Span setStrikethrough(boolean strikethrough) {
isStrikethrough = strikethrough;
return this;
}
public Span setSpannable(ParcelableSpan spannable) {
this.spannable = spannable;
return this;
}
}
}
因為是用java寫的,所以設置成一個鏈式調(diào)用的方式最終看起來會比較美觀。Span表示每一段文字的效果,lp和rp是指向每段文字的范圍,其它的地方應該都能很容易看懂。
然后在使用的時候這樣調(diào)用
TextView testTv = findViewById(R.id.tv_test);
testTv.setTextColor(Color.parseColor("#ffffff"));
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.orange));
CharSequence charSequence = new SpanStringUtils(this)
.append(new SpanStringUtils.Span().setText("abcde").setTextColor(R.color.blue))
.append(new SpanStringUtils.Span().setText("qqqq").setBackgroundColor(R.color.blue))
.append(new SpanStringUtils.Span().setText("ccc").setRelativeSize(1.5f))
.append(new SpanStringUtils.Span().setText("dddddd"))
.append(new SpanStringUtils.Span().setText("eee").setSpannable(foregroundColorSpan))
.append(new SpanStringUtils.Span().setText("8s8s8s8s").setStyle(Typeface.BOLD))
.append(new SpanStringUtils.Span().setText("kk").setUnderline(true))
.append(new SpanStringUtils.Span().setText("M").setStrikethrough(true))
.append(new SpanStringUtils.Span()
.setText("LAST")
.setTextColor(R.color.jh_orange)
.setRelativeSize(3f)
.setUnderline(true)
.setStrikethrough(true))
.create();
testTv.setText(charSequence);
前面的都是單個效果,dddddd是不設效果,最后一個是混合效果,來看看執(zhí)行的結(jié)果

最后說一下,kotlin的話,不需要這樣的方式,它能有更簡潔的封裝方式去實現(xiàn)這樣的效果,我這里就不過多介紹了。
更多關(guān)于Android設置TextView樣式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android TextView控件文字添加下劃線的實現(xiàn)方法
下面小編就為大家?guī)硪黄狝ndroid TextView控件文字添加下劃線的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09
Android Studio 新手入門教程(一)基本設置圖解
這篇文章主要介紹了Android Studio 新手入門教程(一)基本設置圖解,需要的朋友可以參考下2017-12-12
Android RecycleView滑動停止后自動吸附效果的實現(xiàn)代碼(滑動定位)
這篇文章主要介紹了Android RecycleView滑動停止后自動吸附效果的實現(xiàn)代碼(滑動定位),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Input系統(tǒng)按鍵事件的分發(fā)處理示例詳解
這篇文章主要為大家介紹了Input系統(tǒng)按鍵事件的分發(fā)處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01

