SpannableString與SpannableStringBuilder

場(chǎng)景

在實(shí)際開發(fā)中,經(jīng)常會(huì)出現(xiàn)一些富文本的樣式(如:局部文本可點(diǎn)擊栅受,超鏈接族铆,一段文本字體大小不一岩四,局部文本加粗等),這樣常規(guī)的設(shè)置文本就無法實(shí)現(xiàn)目的了哥攘。

針對(duì)這種場(chǎng)景一些常規(guī)的實(shí)現(xiàn):

  1. 利用多個(gè)View的排布來實(shí)現(xiàn)剖煌;
  2. 利用Html實(shí)現(xiàn)富文本格式,在通過Html.getText(html)來解析逝淹;
  3. 利用SpannableString;

方案分析:

  1. 使用方案一會(huì)在布局中新增出多個(gè)View耕姊,導(dǎo)致布局文件臃腫,并且View的inflate是一件比較耗時(shí)的操作栅葡。當(dāng)然在一些特殊的場(chǎng)景茉兰,為了簡(jiǎn)單快速的實(shí)現(xiàn)目的,這種方案也有應(yīng)用欣簇。另外就是采用此方案有時(shí)并不能完美的實(shí)現(xiàn)我們想要的功能规脸;
  2. 使用方案二,優(yōu)點(diǎn)是可以很好的實(shí)現(xiàn)我們想要的文本樣式熊咽,但缺點(diǎn)也很明顯莫鸭,Html.getText()方法解析html標(biāo)簽是一個(gè)很消耗性能的操作,一般情非得已不推薦使用此方案横殴;
  3. 方案三就是本篇要介紹的對(duì)象被因,SpannableString是Android提供專門用于處理富文本的類,根據(jù)設(shè)置不同的span來實(shí)現(xiàn)不同的文本樣式衫仑。使用一個(gè)TextView通過span的處理梨与,即可實(shí)現(xiàn)目的。

API

SpannaableString與SpannableStringBuilder的區(qū)別就在于builder可以使用insert惑畴、append等系列方法蛋欣。

  1. 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) {
    }
    
  2. public void removeSpan(Object what):移除指定的span如贷;

  3. 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

  1. 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);
    }
    

    效果圖如下:

spannableString-forespan.png
  1. 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)擊后的背景高亮的顯示顏色
    }
    

    效果如下:

clickspan.gif
  1. BackgroundColorSpan

    背景色愁铺,設(shè)置局部的TextView具有背景

  2. MaskFilterSpan

    修飾效果,如模糊(BlurMaskFilter)浮雕(EmbossMaskFilter)

  3. RasterizerSpan

    光柵效果

  4. StrikethroughSpan

    刪除線(中間線)

  5. SuggestionSpan

    相當(dāng)于占位符

  6. UnderlineSpan

    下劃線

  7. 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);
    
  8. DynamicDrawableSpan

    設(shè)置圖片斤贰,基于文本基線或者底部對(duì)齊

  9. ImageSpan

    圖片

  10. RelativeSizeSpan

    相對(duì)大兄前А(文本字體)

    設(shè)置字體相對(duì)大小(相對(duì)值,單位:像素)參數(shù)表示為默認(rèn)字體大小的多少倍

    msp.setSpan(new RelativeSizeSpan(0.5f), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // 0.5f表示默認(rèn)字體大小的一半
    
  11. ReplacementSpan

    父類荧恍,一般不用

  12. MetricAffectingSpan

    父類瓷叫,一般不用

  13. ScaleSpan

    基于X軸縮放

  14. StyleSpan

    new StyleSpan(Typeface.BOLD)
    

    字體樣式:粗體、斜體等

  15. SubscriptSpan

    下標(biāo)(數(shù)學(xué)公式會(huì)用到)

  16. SuperscriptSpan

    上標(biāo)(數(shù)學(xué)公式會(huì)用到)

  17. TextAppearanceSpan

    文本外貌(包括字體送巡、大小摹菠、樣式、顏色)

  18. TypefaceSpan

    文本字體

  19. URLSpan

    文本超鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骗爆,一起剝皮案震驚了整個(gè)濱河市次氨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淮腾,老刑警劉巖糟需,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谷朝,居然都是意外死亡洲押,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門圆凰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杈帐,“玉大人,你說我怎么就攤上這事专钉√敉” “怎么了?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵跃须,是天一觀的道長(zhǎng)站叼。 經(jīng)常有香客問我,道長(zhǎng)菇民,這世上最難降的妖魔是什么尽楔? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮第练,結(jié)果婚禮上阔馋,老公的妹妹穿的比我還像新娘。我一直安慰自己娇掏,他們只是感情好呕寝,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著婴梧,像睡著了一般下梢。 火紅的嫁衣襯著肌膚如雪客蹋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天怔球,我揣著相機(jī)與錄音嚼酝,去河邊找鬼。 笑死竟坛,一個(gè)胖子當(dāng)著我的面吹牛闽巩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播担汤,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼涎跨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了崭歧?” 一聲冷哼從身側(cè)響起隅很,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎率碾,沒想到半個(gè)月后叔营,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡所宰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年绒尊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仔粥。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡婴谱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躯泰,到底是詐尸還是另有隱情谭羔,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布麦向,位于F島的核電站瘟裸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏诵竭。R本人自食惡果不足惜景描,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秀撇。 院中可真熱鬧,春花似錦向族、人聲如沸呵燕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽再扭。三九已至氧苍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泛范,已是汗流浹背让虐。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罢荡,地道東北人赡突。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像区赵,于是被迫代替她去往敵國和親惭缰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容