場(chǎng)景
在實(shí)際開發(fā)中,經(jīng)常會(huì)出現(xiàn)一些富文本的樣式(如:局部文本可點(diǎn)擊栅受,超鏈接族铆,一段文本字體大小不一岩四,局部文本加粗等),這樣常規(guī)的設(shè)置文本就無法實(shí)現(xiàn)目的了哥攘。
針對(duì)這種場(chǎng)景一些常規(guī)的實(shí)現(xiàn):
- 利用多個(gè)View的排布來實(shí)現(xiàn)剖煌;
- 利用Html實(shí)現(xiàn)富文本格式,在通過Html.getText(html)來解析逝淹;
- 利用SpannableString;
方案分析:
- 使用方案一會(huì)在布局中新增出多個(gè)View耕姊,導(dǎo)致布局文件臃腫,并且View的inflate是一件比較耗時(shí)的操作栅葡。當(dāng)然在一些特殊的場(chǎng)景茉兰,為了簡(jiǎn)單快速的實(shí)現(xiàn)目的,這種方案也有應(yīng)用欣簇。另外就是采用此方案有時(shí)并不能完美的實(shí)現(xiàn)我們想要的功能规脸;
- 使用方案二,優(yōu)點(diǎn)是可以很好的實(shí)現(xiàn)我們想要的文本樣式熊咽,但缺點(diǎn)也很明顯莫鸭,Html.getText()方法解析html標(biāo)簽是一個(gè)很消耗性能的操作,一般情非得已不推薦使用此方案横殴;
- 方案三就是本篇要介紹的對(duì)象被因,SpannableString是Android提供專門用于處理富文本的類,根據(jù)設(shè)置不同的span來實(shí)現(xiàn)不同的文本樣式衫仑。使用一個(gè)TextView通過span的處理梨与,即可實(shí)現(xiàn)目的。
API
SpannaableString與SpannableStringBuilder的區(qū)別就在于builder可以使用insert惑畴、append等系列方法蛋欣。
-
public void setSpan():設(shè)置span,一切富文本的實(shí)現(xiàn)都是通過此方法的來設(shè)置不同效果的span來實(shí)現(xiàn)的。
/** * * @param what 具體的實(shí)現(xiàn)效果的Span類對(duì)象 * @param start span生效的起始下標(biāo) * @param end span生效的終止下標(biāo)+1 * @param flags span效果針對(duì)臨界位置的insert是否擴(kuò)散生效 */ public void setSpan(Object what, int start, int end, int flags) { }
public void removeSpan(Object what):移除指定的span如贷;
-
insert/delete/append等方法是SpannableStringBuilder所有的方法系列陷虎,其中setSpan()中的flags參數(shù)就是配合這些方法的使用而發(fā)揮效果的到踏。
flags的選項(xiàng)在Spanned接口中,分別為:
- SPAN_INCLUSIVE_EXCLUSIVE:包含start尚猿,不包含end
- SPAN_INCLUSIVE_INCLUSIVE:start,end都包含
- SPAN_EXCLUSIVE_EXCLUSIVE:start,end都不包含
- SPAN_EXCLUSIVE_INCLUSIVE:start不包含窝稿,end包含
具體生效備注如下:
Spanned中flags的標(biāo)記,是在SpannableStringBuilder中使用的凿掂,在SpannableString中沒有作用伴榔。當(dāng)使用了SpannableStringBuilder.insert(int,CharSeque)系列方法后,對(duì)于insert后的字符串是否進(jìn)行擴(kuò)展特性的標(biāo)記庄萎,并且此標(biāo)記作用的場(chǎng)景也僅僅是insert的位置恰好處于start或者end兩個(gè)端點(diǎn)的臨界位置踪少,即用flags標(biāo)記這個(gè)臨界點(diǎn)跟隨哪個(gè),是否使用span的特性糠涛。
各種Span
-
ForegroundColorSpan
用于設(shè)置前景色援奢,即設(shè)置字體的顏色
void forefroundColorSpan() { TextView tv1 = new TextView(activity); /** * Spanned中flags的標(biāo)記,是在SpannableStringBuilder中使用的忍捡,在SpannableString中沒有作用集漾。并且其使用場(chǎng)景是當(dāng) 使用了SpannableStringBuilder.insert(int,CharSeque)方法后,砸脊,對(duì)于insert后的字符串是否進(jìn)行擴(kuò)展特性的標(biāo)記具篇,, 并且此標(biāo)記作用的場(chǎng)景也僅僅是insert的位置恰好處于start 或者 end兩個(gè)端點(diǎn)的臨界位置凌埂,驱显,,即用flags標(biāo)記這個(gè)臨界點(diǎn)跟隨哪個(gè)侨舆。 * */ SpannableStringBuilder ss = new SpannableStringBuilder("手續(xù)費(fèi)84.00元"); ForegroundColorSpan span1 = new ForegroundColorSpan(Color.RED); ss.setSpan(span1, 3, 8, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); tv1.setText(ss); rootSpannable.addView(tv1); //插入的9擴(kuò)展了特性秒紧,而插入的5未擴(kuò)展特性 ss.insert(3, "9").insert(9, "5"); TextView tv2 = new TextView(activity); tv2.setText(ss); rootSpannable.addView(tv2); //移除指定span ss.removeSpan(span1); TextView tv5 = new TextView(activity); tv5.setText(ss); rootSpannable.addView(tv5); //恢復(fù)ss ss = new SpannableStringBuilder("手續(xù)費(fèi)84.00元"); ss.setSpan(span1, 3, 8, Spanned.SPAN_EXCLUSIVE_INCLUSIVE); //驗(yàn)證同樣的情況,只要執(zhí)行insert系列方法挨下,,即使flags改變效果也不變 TextView tv3 = new TextView(activity); tv3.setText(ss); rootSpannable.addView(tv3); //插入的9未擴(kuò)展特性脐湾,而插入的5擴(kuò)展了特性 ss.insert(3, "9").insert(9, "5"); TextView tv4 = new TextView(activity); tv4.setText(ss); rootSpannable.addView(tv4); }
效果圖如下:
-
ClickableSpan
設(shè)置局部文本可點(diǎn)擊
void clickableSpan() { ClickableSpan clickableSpan = new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { ds.setColor(Color.BLUE);//控制可點(diǎn)擊文案的字體顏色 ds.setUnderlineText(false);//可點(diǎn)擊文案是否具有下劃線 } @Override public void onClick(View widget) { MyToast.showShort(getContext(), "clicked"); } }; SpannableString ss = getSS(); ss.setSpan(clickableSpan, 0, 3, Spanned.SPAN_EXCLUSIVE_INCLUSIVE); TextView tv = getTv(); tv.setText(ss); tv.setMovementMethod(LinkMovementMethod.getInstance()); //一般由于頁面的數(shù)據(jù)刷險(xiǎn)等原因臭笆,為避免重復(fù)設(shè)置MovementMethod,在setMovementMethod之前做如下下判斷 /*MovementMethod m = tv.getMovementMethod(); if (m == null || !(m instanceof LinkMovementMethod)) { if (tv.getLinksClickable()) { tv.setMovementMethod(LinkMovementMethod.getInstance()); } }*/ tv.setHighlightColor(Color.YELLOW);//更改可點(diǎn)擊區(qū)域文本秤掌,觸摸或者點(diǎn)擊后的背景高亮的顯示顏色 }
效果如下:
-
BackgroundColorSpan
背景色愁铺,設(shè)置局部的TextView具有背景
-
MaskFilterSpan
修飾效果,如模糊(BlurMaskFilter)浮雕(EmbossMaskFilter)
-
RasterizerSpan
光柵效果
-
StrikethroughSpan
刪除線(中間線)
-
SuggestionSpan
相當(dāng)于占位符
-
UnderlineSpan
下劃線
-
AbsoluteSizeSpan
絕對(duì)大形偶(文本字體)
// 設(shè)置字體絕對(duì)大幸鹇摇(絕對(duì)值,單位:像素) msp.setSpan(new AbsoluteSizeSpan(20), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // 第二個(gè)參數(shù)boolean dip,如果為true孟岛,表示前面的字體大小單位為dip瓶竭,否則為像素督勺,同上。 msp.setSpan(new AbsoluteSizeSpan(20, true), 6, 8,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-
DynamicDrawableSpan
設(shè)置圖片斤贰,基于文本基線或者底部對(duì)齊
-
ImageSpan
圖片
-
RelativeSizeSpan
相對(duì)大兄前А(文本字體)
設(shè)置字體相對(duì)大小(相對(duì)值,單位:像素)參數(shù)表示為默認(rèn)字體大小的多少倍
msp.setSpan(new RelativeSizeSpan(0.5f), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // 0.5f表示默認(rèn)字體大小的一半
-
ReplacementSpan
父類荧恍,一般不用
-
MetricAffectingSpan
父類瓷叫,一般不用
-
ScaleSpan
基于X軸縮放
-
StyleSpan
new StyleSpan(Typeface.BOLD)
字體樣式:粗體、斜體等
-
SubscriptSpan
下標(biāo)(數(shù)學(xué)公式會(huì)用到)
-
SuperscriptSpan
上標(biāo)(數(shù)學(xué)公式會(huì)用到)
-
TextAppearanceSpan
文本外貌(包括字體送巡、大小摹菠、樣式、顏色)
-
TypefaceSpan
文本字體
-
URLSpan
文本超鏈接