textview - SpannableString 小工具

2018-09-11  本文已影响101人  前行的乌龟

昨天总结了下 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
    }

}

参考资料


上一篇下一篇

猜你喜欢

热点阅读