Android之SpannableString、SpannableStringBuilder總結

codeFei發表於2018-09-30

SpannableString

String字串,這個我們們經常用,一定很熟悉,而這個SpanableString這個就不常用了,其實它們都可以表示字串,只不過後者可以輕鬆地利用官方提供的Api對字串進行各種風格的設定。

日常開發中都有哪些應用場景呢?比如:

  • 顯示的文字加上下劃線、中劃線、斜體、加粗等
  • 給TextView中部分文字加上點選事件或顏色背景
  • TextView中部分文字需要顯示的字型大,部分文字需要顯示的字型小
  • TextView中的文字可要求顯示錶情符號(在聊天應用中經常會出現)等等等

這點需求雖說實現起來不是什麼難事,不過選擇一個好的方案,可以事半功倍。接下來介紹今天的主角:SpannableString

先看看官方怎麼定義這個類的

This is the class for text whose content is immutable but to which markup objects can be attached and detached. For mutable text, see SpannableStringBuilder.
複製程式碼

大體意思是:這是文字的類,該文字的內容是不可變的,但可以附加和分離標記物件。對於可變文字,請參見SpannableStringBuilder。

這個類原始碼很少,100行程式碼都不到,感興趣的可以去看看。其中有一個核心方法:setSpan(what,start,end,flags)共有4個引數

  1. what:是一個Object物件,用來設定字串的顯示風格(其中官方已經給我們提供一些常用的Span類,當然也可以自己定義了)
  2. sart:從字串的第幾位開始,設定的風格起作用
  3. end:設定的風格到第幾位後,不在起作用;其實與start構成了一個作用區間
  4. flags:有四種形式,就是確定作用空間是否包括收尾,待會說

常用的Span類有:

  1. BackgroundColorSpan 背景色
  2. ClickableSpan 文字可點選,有點選事件
  3. ForegroundColorSpan 文字顏色(前景色)
  4. MaskFilterSpan 修飾效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
  5. MetricAffectingSpan 父類,一般不用
  6. RasterizerSpan 光柵效果
  7. StrikethroughSpan 刪除線(中劃線)
  8. SuggestionSpan 相當於佔位符
  9. UnderlineSpan 下劃線
  10. AbsoluteSizeSpan 絕對大小(文字字型)
  11. DynamicDrawableSpan 設定圖片,基於文字基線或底部對齊。
  12. ImageSpan 圖片
  13. RelativeSizeSpan 相對大小(文字字型)
  14. ReplacementSpan 父類,一般不用
  15. ScaleXSpan 基於x軸縮放
  16. StyleSpan 字型樣式:粗體、斜體等
  17. SubscriptSpan 下標(數學公式會用到)
  18. SuperscriptSpan 上標(數學公式會用到)
  19. TextAppearanceSpan 文字外貌(包括字型、大小、樣式和顏色)
  20. TypefaceSpan 文字字型
  21. URLSpan 文字超連結

flags共有四種屬性:

  1. Spanned.SPAN_INCLUSIVE_EXCLUSIVE 從起始下標到終了下標,包括起始下標
  2. Spanned.SPAN_INCLUSIVE_INCLUSIVE從起始下標到終了下標,同時包括起始下標和終了下標
  3. Spanned.SPAN_EXCLUSIVE_EXCLUSIVE從起始下標到終了下標,但都不包括起始下標和終了下標
  4. Spanned.SPAN_EXCLUSIVE_INCLUSIVE 從起始下標到終了下標,包括終了下標

事例

  • ForegroundColorSpan :給一段文字中個別的字設定顏色,這個比較常用了
    圖1
    ForegroundColorSpan,為文字設定前景色,效果和TextView的setTextColor()類似,不過如果用setTextColor()估計得用TextView拼接或者用到Html類載入html片段實現。ForegroundColorSpan,實現如下:
        TextView txtInfo = findViewById(R.id.textView);
        SpannableString span = new SpannableString("設定前背景色");
        span.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorPrimary)),3, 5, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        txtInfo.setMovementMethod(LinkMovementMethod.getInstance());
        txtInfo.setHighlightColor(getResources().getColor(android.R.color.transparent));
        txtInfo.setText(span);
複製程式碼
  • ImageSpan:在文字中顯示錶情符號(其實就是設定圖片)
    圖2
    如果對一段文字中特殊文字進行處理,就可以實現聊天效果中帶有表情符。 怎麼實現呢,程式碼如下,其實我們知道有這個用法就行了
        TextView tv8 = findViewById(R.id.tv8);
        SpannableString spanStr8 = new SpannableString("文字裡新增表情(表情)");
        Drawable image = getResources().getDrawable(R.mipmap.ic_launcher);
        image.setBounds(new Rect(0,0,50,50));
        spanStr8.setSpan(new ImageSpan(image),5, 7,Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        tv8.setText(spanStr8);
複製程式碼
  • ClickableSpan:可以為文字加上點選事件,比如常見的:
    圖3
    實現方式:
        SpannableString spanStr10 = new SpannableString("請準守協議《XXXXXX協議》");
        spanStr10.setSpan(new ClickableSpan() {
            @Override
            public void onClick(View view) {
                //點選事件
                Toast.makeText(MainActivity.this,"點選了我,可以寫跳轉邏輯",Toast.LENGTH_SHORT).show();
            }
            @Override
            public void updateDrawState(TextPaint ds) {
                ds.setColor(Color.parseColor("#ff4d40"));
            }
        },5,spanStr10.length(),Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        tv10.setMovementMethod(LinkMovementMethod.getInstance()); // 必須的設定這個,不然點選效果 不生效
        tv10.setHighlightColor(Color.parseColor("#ffffff")); //點選後顯示的背景色,我這裡設定了白色,預設顏色不好看
        tv10.setText(spanStr10);
複製程式碼

還有其它一些常規用法,我就不一一列舉了,上圖:

圖3
github地址:github.com/A-How/Spana…

SpanableStringBuilder

定義字串用String,對於大量字串進行拼接,我們可以使用StringBuilder進行處理;SpanableStringBuilder也是對大量SpanableString拼接進行處理的,也同樣使用append方法。舉個例子:

圖4
程式碼實現

        String beforeText = "快快下單";
        String afterText = "(立享200元優惠)";
        int beforeSize = 20;
        int afterSize = 15;
        SpannableStringBuilder builder = new SpannableStringBuilder(beforeText);
        builder.setSpan(new ForegroundColorSpan(Color.parseColor("#ffdf40")),0,beforeText.length(),Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        builder.setSpan(new AbsoluteSizeSpan(beforeSize,true),0,beforeText.length(),Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        builder.append(afterText);
        builder.setSpan(new ForegroundColorSpan(Color.parseColor("#ff6940")),beforeText.length(),builder.length(),Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        builder.setSpan(new AbsoluteSizeSpan(afterSize,true),beforeText.length(),builder.length(),Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        tv12.setText(builder);
複製程式碼

後續我會繼續新增一些關於SpanableString一些Span類的用法, github地址:github.com/A-How/Spana…

相關文章