textview - SpannableString 小工具

昨天總結了下 SpannableString 的用法,在學習之后發現 SpannableString 還是能干很多事的,我的印象里記得 SpannableString 也就是能改個顏色,改個大小。所以這次看完也不知道記憶能保鮮多久,怕忘,想了想還是寫個小工具好些,一是加強印象,這寫和不寫完全是2個概念,二是以后也方便用

項目地址:BW_Libs

Snip20180910_4.png

代碼設計


  1. 首先像 SpannableString 這種功能單一,類很少的,只能成為 utils 工具,而不能叫 lib 庫的,所以起名就叫 SpanUtils 好了
        SpanUtils
                .with(tx01)
                .foregroundColor(Color.BLUE, tx01.text.indexOf("-") + 1, tx01.text.length)
                .show()
  1. 工具類一般都需要有統一的入口的,所以我們使用 kotlin + 靜態單例的方式來提供工具使用規范。為了趕上鏈式調用的春風,可以不停的 . 下去,所以我們就不能直接返回 SpannableString 對象了,而是我們寫的 SpannableString 功能包裝類。開始的資源綁定方法,我們提供2個重載,可以接受 String 和 TextView
    companion object {

        fun with(text: String): SpanUtils {
            return SpanUtils(text)
        }

        fun with(textView: TextView): SpanUtils {
            return SpanUtils(textView, textView.text.toString())
        }
    }
  1. 最后我們也提供顯示的重載,除了可以使用已經綁定的 TextView 外,也可以指定 TextView,

    fun show() {
        textView?.setText(spannable)
    }

    fun show(textView: TextView?) {
        textView?.setText(spannable)
    }

  1. 然后我們再提供獲取最終的 String 和 SpannableString 的方法

    fun getString(): String {
        return spannable.toString()
    }

    fun getSpannableString(): SpannableString {
        return spannable
    }
  1. 這樣的話這個小工具基本就齊活了,在使用上也能做到比較靈活了。我一直覺得小的進步積累多了之后就是巨大的改變,這樣的技術進步才是最穩的,不知不覺的我們就可以寫出不錯的能看的工具,庫,組件出來了。

最后代碼


class SpanUtils(text: String) {

    // SpannableString 文字樣式對象
    lateinit var spannable: SpannableString
    // 關聯的 view
    var textView: TextView? = null

    companion object {

        /**
         * 全局靜態入口
         */
        fun with(text: String): SpanUtils {
            return SpanUtils(text)
        }

        /**
         * 全局靜態入口
         */
        fun with(textView: TextView): SpanUtils {
            return SpanUtils(textView, textView.text.toString())
        }
    }

    /**
     * 主構造函數里,初始化 SpannableString 對象
     */
    init {
        this.spannable = SpannableString(text)
    }

    constructor(textView: TextView, text: String) : this(text) {
        this.textView = textView
    }

    /**
     * 返回最終結果
     */
    fun getString(): String {
        return spannable.toString()
    }

    /**
     * 返回最終結果
     */
    fun getSpannableString(): SpannableString {
        return spannable
    }

    /**
     * 顯示
     */
    fun show() {
        textView?.setText(spannable)
    }

    /**
     * 顯示
     */
    fun show(textView: TextView?) {
        textView?.setText(spannable)
    }

    /**
     * 添加前景色
     */
    fun foregroundColor(color: Int, startIndex: Int, endIndex: Int): SpanUtils {
        var forColorSpan = ForegroundColorSpan(color)
        spannable.setSpan(forColorSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 添加前景色
     */
    fun backgroundColor(color: Int, startIndex: Int, endIndex: Int): SpanUtils {
        var backColorSpan = BackgroundColorSpan(color)
        spannable.setSpan(backColorSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 相對文字大小
     * size: 應使用諸如 1.2F 這樣的參數格式
     */
    fun relativeTextSize(size: Float, startIndex: Int, endIndex: Int): SpanUtils {
        var relativeSizeSpan = RelativeSizeSpan(size)
        spannable.setSpan(relativeSizeSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 絕對文字大小
     * size: 應使用 sp 轉換成的 int 值
     */
    fun absoluteTextSize(size: Int, startIndex: Int, endIndex: Int): SpanUtils {
        var absoluteSizeSpan = AbsoluteSizeSpan(size)
        spannable.setSpan(absoluteSizeSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 中劃線
     */
    fun middleLine(startIndex: Int, endIndex: Int): SpanUtils {
        var strikethroughSpan = StrikethroughSpan()
        spannable.setSpan(strikethroughSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 下劃線
     */
    fun underLine(startIndex: Int, endIndex: Int): SpanUtils {
        var underLineSpan = UnderlineSpan()
        spannable.setSpan(underLineSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 上標
     * 請允許我使用自創單詞,因為原生單詞實在不好記憶,也容易和下標混淆
     */
    fun topFlag(startIndex: Int, endIndex: Int): SpanUtils {
        var superscriptSpan = SuperscriptSpan()
        spannable.setSpan(superscriptSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 下標
     * 請允許我使用自創單詞,因為原生單詞實在不好記憶,也容易和上標混淆
     */
    fun bottomFlag(startIndex: Int, endIndex: Int): SpanUtils {
        var subscriptSpan = SubscriptSpan()
        spannable.setSpan(subscriptSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 粗體
     */
    fun bold(startIndex: Int, endIndex: Int): SpanUtils {
        var boldSpan = StyleSpan(Typeface.BOLD)
        spannable.setSpan(boldSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 斜體
     */
    fun italic(startIndex: Int, endIndex: Int): SpanUtils {
        var italicSpan = StyleSpan(Typeface.ITALIC)
        spannable.setSpan(italicSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 斜粗體
     */
    fun italicAndBlod(startIndex: Int, endIndex: Int): SpanUtils {
        var italicAndBlodSpan = StyleSpan(Typeface.BOLD_ITALIC)
        spannable.setSpan(italicAndBlodSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 斜粗體
     * drawable: 圖片必須顯示的指名大小,才能有效顯示,請參考 - drawable.setBounds(0, 0, 80, 80)
     */
    fun image(drawable: Drawable, startIndex: Int, endIndex: Int): SpanUtils {
        var imageSpan = ImageSpan(drawable)
        spannable.setSpan(imageSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        return this@SpanUtils
    }

    /**
     * 可點擊區域
     * textView: 必須設置 setMovementMethod() 方法才能實現點擊
     */
    fun clickable(textView: TextView, ClickableSpan: ClickableSpan, startIndex: Int, endIndex: Int): SpanUtils {
        spannable.setSpan(ClickableSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        textView.setMovementMethod(LinkMovementMethod.getInstance())
        return this@SpanUtils
    }

    /**
     * 超鏈接
     * adress: 必須加 http:// 協議才能正常跳轉到系統瀏覽器
     */
    fun url(textView: TextView, adress: String, startIndex: Int, endIndex: Int): SpanUtils {
        var urlSpan = URLSpan(adress)
        spannable.setSpan(urlSpan, startIndex, endIndex, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE)
        textView.setMovementMethod(LinkMovementMethod.getInstance())
        return this@SpanUtils
    }

}

參考資料


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容