SpannableStringBuilder 的使用

前言

最近在作需求的時候,常常會有一個文本內,須要單獨高亮其中一部分,而且支持這部分的單獨點擊事件。bash

要實現這樣的功能一般有下面幾種實現方式:app

  1. 使用多個 TextView 進行拼接顯示
  2. 在 TextView 中加載 Html
  3. 使用 SpannableString / SpannableStringBuilder

第一個方案的靈活性不足,這裏不考慮。ide

第二個方案則是使用 HTML 標籤包裹字符串,而後使用 Html.fromHtml(str) 獲得渲染後的字符串,設置給 TextView。這種方法,處理點擊事件比較麻煩,若是想彈出本地的彈窗或者跳轉到另外一個Activity,可能須要經過 JS 注入的方式進行實現。字體

因此最常使用的方案是第三個,SpannableString 或 SpannableStringBuilder 的功能很是強大,可讓一個 TextView 變得豐富多彩,下面來具體看看。ui

SpannableStringBuilder 和 SpannableString

SpannableStringBuilder 和 SpannableString 均可以用來顯示富文本,它們的關係就像 StringBuilder 和 String 的關係同樣,SpannableStringBuilder 能夠拼接字符串,SpannableString 不能夠。它們都實現了 Spannable接口。this

img1

Spanspa

SpannableStringBuilder 主要經過 setSpan(Object what, int start, int end, int flags) 這個方法設置不一樣的 Span,改本文本樣式,setSpan 方法能夠屢次調用.net

參數解釋:3d

start:開始位置下標 end:結束位置下標,不包含code

what:各類 Span 實例

下面表格中列出部分可用的 Span:

Span 含義 備註
BackgroundColorSpan 設置文本背景顏色 參數傳入一個int類型的顏色值便可
ForegroundColorSpan 設置文本顏色 參數傳入一個int類型的顏色值便可
ClickableSpan 設置點擊事件 須要繼承這個類重寫onClick方法
StrikethroughSpan 設置刪除線效果 無參
UnderlineSpan 設置下劃線效果 無參
AbsoluteSizeSpan 設置文字的絕對大小 第一個參數爲字體大小,只有這一個參數時,單位爲px,第二個參數dip,默認爲false,設爲true時,第一個參數size的單位是dp
RelativeSizeSpan 設置文字的相對大小
StyleSpan 設置文字粗體、斜體 Typeface.BOLD爲粗體,Typeface.ITALIC爲斜體, Typeface.BOLD_ITALIC爲粗斜體,做爲參數傳入便可
ImageSpan 設置圖片 將[start,end)範圍內的文字替換成參數傳入的圖片
MaskFilterSpan 修飾效果,如模糊(BlurMaskFilter)浮雕
RasterizerSpan 光柵效果
SuggestionSpan 至關於佔位符
DynamicDrawableSpan 設置圖片,基於文本基線或底部對齊
ScaleXSpan 基於x軸縮放
SubscriptSpan 下標(數學公式會用到)
SuperscriptSpan 上標(數學公式會用到)
TextAppearanceSpan 文本外貌(包括字體、大小、樣式和顏色)
TypefaceSpan 文本字體
URLSpan 文本超連接

flag:取值有如下四個

flag 含義
SPAN_EXCLUSIVE_EXCLUSIVE 在文本前面或後面插入新的文本時,都不會應用該樣式(前面不包括,後面不包括)
SPAN_EXCLUSIVE_INCLUSIVE 在文本前插入新的文本不會應用該樣式,而在文本後插入新文本會應用該樣式(前面不包括,後面包括)
SPAN_INCLUSIVE_EXCLUSIVE 在文本前插入新的文本會應用該樣式,而在文本後插入新文本不會應用該樣式(前面包括,後面不包括)
SPAN_INCLUSIVE_INCLUSIVE 在文本前面或後面插入新的文本時,都會應用該樣式(前面包括,後面包括)

EXCLUSIVE:排除的,即不包含 ,INCLUSIVE:包含的。大多使用第一個,先後均不包含。

示例

選擇了其中幾個經常使用 Span 作了個簡單示例,代碼以下:

class SpannableAcitivity : AppCompatActivity() {

    val textStr = "夜闌臥聽風吹雨,鐵馬冰河入夢來"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_spannable)
        var builder = SpannableStringBuilder().also {
            it.append(textStr)
            it.setSpan(ForegroundColorSpan(Color.BLUE), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(BackgroundColorSpan(Color.RED), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(object : ClickableSpan() {
                override fun onClick(widget: View) {
                    Toast.makeText(this@SpannableAcitivity, "聽風吹雨", Toast.LENGTH_SHORT).show()
                }
            }, 3, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(StrikethroughSpan(), 8, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(UnderlineSpan(), 9, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(AbsoluteSizeSpan(50), 10, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(StyleSpan(Typeface.BOLD), 11, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
            it.setSpan(ImageSpan(this@SpannableAcitivity, R.mipmap.ic_launcher),
                12, 13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
        spannable_tv.text = builder
        spannable_tv.movementMethod = LinkMovementMethod.getInstance()
    }
}
複製代碼

效果如圖:

img2

ClickableSpan 注意

在使用 ClickableSpan 時,須要注意如下幾點:

  1. 有默認顏色和下滑線,若是想修改顏色或去掉下劃線,須要重寫 updateDrawState方法。
@Override public void updateDrawState(@NonNull TextPaint ds) {
    super.updateDrawState(ds);
    ds.setColor(getResources().getColor(R.color.color_black));
    ds.setUnderlineText(false);
}
複製代碼
  1. 設置 ClickableSpan 後,TextView 須要加一行textView.setMovementMethod(LinkMovementMethod.getInstance());,不然ClickableSpan部分點擊事件不起做用。

  2. 設置 ClickableSpan,可能會與 TextView 自己的onClick事件有衝突。

參考資料

Android-TextView設置多種顏色及部分點擊事件

【Android】強大的SpannableStringBuilder

相關文章
相關標籤/搜索