官方core-ktx庫能對富文字Span開發帶來哪些便利2

語言: CN / TW / HK

theme: juejin highlight: atelier-heath-light


這是一個系列文章,專門研究Android官方提供的core-ktx庫裡面的擴充套件類、方法等等,看看能為專案開發帶來哪些便利。 已更新的文章列表如下:

你需要了解的官方core-ktx庫能對開發帶來哪些便利1

接下來,本篇文章就帶你看下富文字開發中使用到的Spancore-ktx庫會為其帶來怎樣的使用便利。

當前SpannableStringBuilder的使用現狀

kotlin private fun test() { val stringBuilder = SpannableStringBuilder() var length = stringBuilder.length stringBuilder.append("開始了") //設定文字大小 stringBuilder.setSpan( RelativeSizeSpan(20f), length, stringBuilder.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE ) length = stringBuilder.length stringBuilder.append("執行了") //設定背景顏色 stringBuilder.setSpan( BackgroundColorSpan(Color.parseColor("#ffffff")), length, stringBuilder.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE ) length = stringBuilder.length stringBuilder.append("結束了") //設定點選事件 stringBuilder.setSpan( object : ClickableSpan() { override fun onClick(widget: View) { } }, length, stringBuilder.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE ) }

以上程式碼就實現了三個功能,設定文字大小、背景顏色及點選事件,卻寫了這麼一大坨程式碼,寫起來好麻煩!!

core-ktx庫的SpannableStringBuilder擴充套件

  1. 看下如何構造一個SpannableStringBuilder:

    image.png

    我們就可以在程式碼中這樣使用: kotlin private fun test4() { val build = buildSpannedString { //操作各種Span } }

    請注意,這個buildSpannedString()方法的函式型別屬於帶接收者的函式型別,意為著我們可以訪問SpannableStringBuilder定義的公共的屬性方法(包括擴充套件方法),接下來我們就看下core-ktx庫為SpannableStringBuilder提供了哪些擴充套件方法。

  2. SpannableStringBuilder.backgroundColor()設定背景色:

    image.png

    這個擴充套件方法需要傳入一個顏色值充當背景色,backgroundColor()會自動幫助我們建立一個ForegroundColorSpan物件;還可以傳入一個函式型別builderAction,比如用作使用append()方法設定要渲染的文字內容,最終會呼叫到inSpan()方法:

    image.png

    是不是明白了,最終我們是在這個方法中將xxxSpan設定給SpannableStringBuilder的。最終就可以這樣使用了:

    kotlin val build = buildSpannedString { //操作各種Span backgroundColor(Color.RED) { append("開始了") } }

  3. SpannableStringBuilder.bold()設定粗體:

    image.png

    可以看到bold()方法中會自動幫助我們建立一個StyleSpan物件,使用起來和上面差不多: kotlin val build = buildSpannedString { bold { append("開始了") } }

  4. 其他SpannableStringBuilder.xxx()富文字設定擴充套件:

core-ktx庫提供了很多富文字設定的擴充套件方法,這裡就只介紹上面的兩個,其他的就不再這裡介紹了,可以自行看下原始碼:

![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c86fe90188b8418ebbe06098bbd011e3~tplv-k3u1fbpfcp-watermark.image?)
  1. 一個非常非常簡單的使用技巧 > 假設當前有一小段文字遮天是一群人的完美,完美是一個人的遮天,我想要對整段文字設定一個背景色,對一群人這三個字設定一個粗體大小,利用上面core-ktx庫提供的擴充套件,我們可以這樣實現:

    kotlin private fun test4() { val build = buildSpannedString { backgroundColor(Color.RED) { append("遮天是") bold { append("一群人") } append("的完美,完美是一個人的遮天") } } }

    核心就是SpannableStringBuilder.xxx()系列的富文字擴充套件方法的第二個引數是一個接收者為SpannableStringBuilder的函式型別,所以backgroundColor()bold()strikeThrough()等等可以相互巢狀使用,從來更簡單的實現一些富文字效果。

使用時請注意,buildSpannedString()這個方法建立的SpannableStringBuilder最終會包裝成一個SpannedString不可變物件,請根據實際情況使用。

core-ktx庫的Spannable擴充套件

SpannableStringBuilderSpannableString等實現了Spannable介面,所以Spannable定義的擴充套件方法對常用的SpannableStringBuilderSpannableString同樣適用。

  1. Spannable.clearSpans清理所有標識(包括各種Span)

    image.png

    使用時,直接對Spannable及其子類呼叫clearSpans()即可。

  2. Spannable.set(start: Int, end: Int, span: Any)設定Span

    image.png

    這個擴充套件方法就比較牛逼了,它是一個運算子過載函式且過載了[xxx]運算子來設定Span的,我們看下使用:

    kotlin val stringBuilder = SpannableStringBuilder() //設定背景色 stringBuilder[0, 2] = BackgroundColorSpan(Color.RED)

    有沒有眼前一亮的感覺哈!!

  3. Spannable.set(range: IntRange, span: Any)設定Span

    image.png

    這個方法和上一個方法很像,不過傳入的設定Span標識範圍的方式發生了改變,變成了一個IntRange型別,我們直接看下使用:

    kotlin val stringBuilder = SpannableStringBuilder() //設定背景色 stringBuilder[0..3] = BackgroundColorSpan(Color.RED)

  4. CharSequence.toSpannable()轉換CharSequenceSpannableString

    image.png

    這個很簡單,就不再進行舉例說明了。

core-ktx庫的Spanned擴充套件

Spanned的子介面包括我們上面剛講到的Spannable,所以它定義的擴充套件方法對於SpannableStringBuilderSpannableString同樣適用。

  1. CharSequence.toSpanned()轉換CharSequenceSpannedString

    image.png

    注意和isSpannable()轉換的區別,一個能設定Span,一個不能設。

  2. Spanned.getSpans()獲取指定型別的Span標識

    image.png

    藉助於Kotlin的泛型實化reified+inline簡化了傳入具體Span型別的邏輯,我們看下使用: kotlin private fun test4(builder: SpannableStringBuilder) { val spans = builder.getSpans<BackgroundColorSpan>() } 獲取型別為BackgroudColorSpan的所有Span物件,如果我們想要獲取所有的Span物件,直接將傳入的泛型型別改為Any即可。

  3. Spanned.toHtml()將富文字轉換成同等效果顯示的html程式碼

    image.png

    也就是說如果你富文字中存在ImageSpan,轉換成html程式碼時,就會幫你在對應位置新增一個<img src="" />的標籤,我們簡單看下其核心原始碼Html.withinParagraph()中的片段:

    image.png

富文字繪製複雜佈局的兩種技巧

  1. ReplacementSpan這個Span使用非常靈活,它提供了方法draw()可自定義繪製你想要的佈局效果;

  2. 如果使用ReplacementSpan自定義繪製佈局還是太過於複雜,可以考慮先使用原生元件在xml中實現這個佈局效果,然後將這個xml通過Inflate轉換成View,並將呼叫ViewonDraw()方法,手動繪製到我們自定義Bitmap中,經過這個流程,我們就將這個複雜的佈局轉換成了Bitmap影象,然後使用ImageSpan載入該Bitmap,最終渲染到富文字中即可。

    請注意,請根據實際情況判斷,是否需要先手動測量這個轉換的View,然後再將其繪製到我們自定義的Bitmap中,否則可能不生效。

總結

以上就是core-ktx庫針對於富文字提供的所有擴充套件方法,核心的原始碼就在SpannableStringBuilder.ktSpannableString.ktSpannedString.kt這三個檔案中,大家有需要請自行檢視。