美文网首页
SpannableStringBuiler封装Kotlin

SpannableStringBuiler封装Kotlin

作者: FlyClound | 来源:发表于2021-06-16 22:08 被阅读0次

    前言

    SpannableStringBuilder和SpannableString功能基本一样,不过SpannableStringBuilder可以拼接,主要是通过setSpan来实现各种效果,主要的方法如下:

    start: 指定Span的开始位置
    end: 指定Span的结束位置,并不包括这个位置。
    flags:取值有如下四个
    Spannable. SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式
    Spannable. SPAN_INCLUSIVE_INCLUSIVE:前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式
    Spannable. SPAN_EXCLUSIVE_EXCLUSIVE:前面不包括,后面不包括
    Spannable. SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括
    what: 对应的各种Span,不同的Span对应不同的样式。已知的可用类有:
    BackgroundColorSpan : 文本背景色
    ForegroundColorSpan : 文本颜色
    MaskFilterSpan : 修饰效果,如模糊(BlurMaskFilter)浮雕
    RasterizerSpan : 光栅效果
    StrikethroughSpan : 删除线
    SuggestionSpan : 相当于占位符
    UnderlineSpan : 下划线
    AbsoluteSizeSpan : 文本字体(绝对大小)
    DynamicDrawableSpan : 设置图片,基于文本基线或底部对齐。
    ImageSpan : 图片
    RelativeSizeSpan : 相对大小(文本字体)
    ScaleXSpan : 基于x轴缩放
    StyleSpan : 字体样式:粗体、斜体等
    SubscriptSpan : 下标(数学公式会用到)
    SuperscriptSpan : 上标(数学公式会用到)
    TextAppearanceSpan : 文本外貌(包括字体、大小、样式和颜色)
    TypefaceSpan : 文本字体
    URLSpan : 文本超链接
    ClickableSpan : 点击事件
    

    简单使用示例

    初始化SpannableString或SpannableStringBuilder,然后设置对应的setPan就可以实现对应的效果。

    SpannableString spannableString = new SpannableString("要设置的内容");
            ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#009ad6"));
            spannableString.setSpan(colorSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            ((TextView)findViewById(R.id.mode1)).setText(spannableString);
    

    具体使用详情可以参考:强大的SpannableStringBuilder

    封装使用

    对很多功能都可以封装,简化使用,这里使用了扩展函数,更方便在Kotlin中使用,不过在Java中也可以使用,使用方法如下:

    第一种情况,要设置的内容已经是一段完整的内容

    注意:链式调用时,只需要初始化第一个src就可以了,后续都会默认使用第一个,如果后续继续初始化src, 会导致前面的设置无效,只有最后一个生效。target和range都是为了确定要改变的文字的范围,两个初始化一个即可。

    1. 对整个字符串设置效果

      src 和target默认等于TextView的text

      //对整个 text 设置方式一,textView已经设置过内容,可以不用初始化src
      tvTvOne.sizeSpan(textSize = 20f)
      //对整个 text 设置方式二
      tvTvOne2.typeSpan(src = "全部文字加粗",target = "全部文字加粗",
        type = SsbKtx.type_bold)
      
    2. 设置部分文字效果

      type 有3个,对应加粗,倾斜,加粗倾斜

      //设置部分文字效果
      //tvTv2.typeSpan(range = 2..4,type = SsbKtx.type_bold)
       tvTv2.typeSpan(target = "部分",type = SsbKtx.type_bold)
      //设置加粗倾斜效果
       tvTv3.typeSpan(range = 0..4,type = SsbKtx.type_bold_italic)
      
    3. 对同一个文字设置多个效果

      对同一个部分做多种效果,只能第一个设置 src, 后续设置会导致前面的无效。

      //        tvTv4.typeSpan(range = 0..4,type = SsbKtx.type_bold_italic)
      //            .foregroundColorIntSpan(range = 0..4,color = Color.GREEN)
      //            .strikethroughSpan(range = 0..4)
              tvTv4.typeSpan(src = "只能这个可以设置 src,后面的再设置会导致前面效果无效",
                  range = 0..4,type = SsbKtx.type_bold_italic)
                  .foregroundColorIntSpan(range = 0..4,color = Color.GREEN)
                  .strikethroughSpan(range = 0..4)
      
    4. 对多个不同的文字分别设置不同的效果

       tvTv5.typeSpan(range = 0..4,type = SsbKtx.type_bold_italic)
                  .foregroundColorIntSpan(range = 7..11,color = Color.BLUE)
      
    5. 设置部分点击

      tvTv6.clickIntSpan(range = 0..4){
                  Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show()
              }
      
    6. 设置部分超链接

      tvTv7.urlSpan(range = 0..4,url = "https://www.baidu.com")
      

    第二种情况,拼接成一个完整的字符串

    1. 拼接成完整的内容

       tvTv8.text = "拼接一段文字"
              tvTv8.appendTypeSpan("加粗",SsbKtx.type_bold)
                  .strikethroughSpan(target = "加粗")//对同一部分文字做多个效果
                  .appendForegroundColorIntSpan("改变字体颜色",Color.RED)
      

      如果想对拼接的内容做多个效果,可以在其后面调用对应的方法,只要traget或是range正确即可。

    完整代码

    object SsbKtx {
        const val flag = SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE
        const val type_bold = Typeface.BOLD
        const val type_italic = Typeface.ITALIC
        const val type_bold_italic = Typeface.BOLD_ITALIC
    
    }
    //-------------------CharSequence相关扩展-----------------------
    /**
     *CharSequence不为 null 或者 empty
     */
    fun CharSequence?.isNotNullOrEmpty() = !isNullOrEmpty()
    
    /**
     *获取一段文字在文字中的范围
     * @param target
     * @return
     */
    fun CharSequence.range(target: CharSequence): IntRange {
        val start = this.indexOf(target.toString())
        return start..(start + target.length)
    }
    
    /**
     *将一段指定的文字改变大小
     * @return
     */
    fun CharSequence.sizeSpan(range: IntRange, textSize: Int): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(AbsoluteSizeSpan(textSize), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *将一段指定的文字,设置类型,是否加粗,倾斜
     * @return
     */
    fun CharSequence.typeSpan(range: IntRange, type: Int): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(StyleSpan(type), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置下划线
     * @param range
     * @return
     */
    fun CharSequence.underlineSpan(range: IntRange): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(UnderlineSpan(), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置删除线
     * @param range
     * @return
     */
    fun CharSequence.strikethroughSpan(range: IntRange): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(StrikethroughSpan(), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置文字颜色
     * @param range
     * @return
     */
    fun CharSequence.foregroundColorSpan(range: IntRange, color: Int = Color.RED): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(ForegroundColorSpan(color), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置文字背景色
     * @param range
     * @return
     */
    fun CharSequence.backgroundColorSpan(range: IntRange, color: Int = Color.RED): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(BackgroundColorSpan(color), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置引用线颜色
     * @param range
     * @return
     */
    fun CharSequence.quoteColorSpan(range: IntRange, color: Int = Color.RED): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(QuoteSpan(color), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置字体大小比例
     * @param range
     * @return
     */
    fun CharSequence.proportionSpan(range: IntRange, proportion: Float): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(RelativeSizeSpan(proportion), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置横向字体大小比例
     * @param range
     * @return
     */
    fun CharSequence.proportionXSpan(range: IntRange, proportion: Float): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(ScaleXSpan(proportion), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置上标
     * @param range
     * @return
     */
    fun CharSequence.superscriptSpan(range: IntRange): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(SuperscriptSpan(), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置下标
     * @param range
     * @return
     */
    fun CharSequence.subscriptSpan(range: IntRange): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(SubscriptSpan(), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置字体
     * @param range
     * @return
     */
    fun CharSequence.fontSpan(range: IntRange, font: String): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(TypefaceSpan(font), range.first, range.last, SsbKtx.flag)
        }
    }
    
    @RequiresApi(Build.VERSION_CODES.P)
    fun CharSequence.fontSpan(range: IntRange, font: Typeface): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(TypefaceSpan(font), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置对齐方式
     * @param range
     * @return
     */
    fun CharSequence.alignSpan(range: IntRange, align: Layout.Alignment): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(AlignmentSpan.Standard(align), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置url,超链接
     * @param range
     * @return
     */
    fun CharSequence.urlSpan(range: IntRange, url: String): CharSequence {
        return SpannableStringBuilder(this).apply {
            setSpan(URLSpan(url), range.first, range.last, SsbKtx.flag)
        }
    }
    
    /**
     *设置click,将一段文字中指定range的文字添加颜色和点击事件
     * @param range
     * @return
     */
    fun CharSequence.clickSpan(
        range: IntRange,
        color: Int = Color.RED,
        isUnderlineText: Boolean = false,
        clickAction: () -> Unit
    ): CharSequence {
        return SpannableString(this).apply {
            val clickableSpan = object : ClickableSpan() {
                override fun onClick(widget: View) {
                    clickAction()
                }
    
                override fun updateDrawState(ds: TextPaint) {
                    ds.color = color
                    ds.isUnderlineText = isUnderlineText
                }
            }
            setSpan(clickableSpan, range.first, range.last, SsbKtx.flag)
        }
    }
    
    
    //-------------------TextView相关扩展--------------------------
    /**
     *设置目标文字大小, src,target 为空时,默认设置整个 text
     * @return
     */
    fun TextView?.sizeSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        @DimenRes textSize: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            textSize == 0 -> this
            range != null -> {
                text = src.sizeSpan(range, ResUtils.getDimensionPixelSize(textSize))
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.sizeSpan(src.range(target!!), ResUtils.getDimensionPixelSize(textSize))
                this
            }
            else -> this
        }
    }
    
    /**
     *设置目标文字大小, src,target 为空时,默认设置整个 text
     * @return
     */
    fun TextView?.sizeSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        textSize: Float
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            textSize == 0f -> this
            range != null -> {
                text = src.sizeSpan(range, DensityUtils.dp2px(textSize))
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.sizeSpan(src.range(target!!), DensityUtils.dp2px(textSize))
                this
            }
            else -> this
        }
    }
    
    /**
     *追加内容设置字体大小
     * @param str
     * @param textSize
     * @return
     */
    fun TextView?.appendSizeSpan(str: String?, textSize: Float): TextView? {
        str?.let {
            this?.append(it.sizeSpan(0..it.length, DensityUtils.dp2px(textSize)))
        }
        return this
    }
    
    fun TextView?.appendSizeSpan(str: String?, @DimenRes textSize: Int): TextView? {
        str?.let {
            this?.append(it.sizeSpan(0..it.length, ResUtils.getDimensionPixelSize(textSize)))
        }
        return this
    }
    
    /**
     *设置目标文字类型(加粗,倾斜,加粗倾斜),src,target 为空时,默认设置整个 text
     * @return
     */
    fun TextView?.typeSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        type: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.typeSpan(range, type)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.typeSpan(src.range(target!!), type)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendTypeSpan(str: String?, type: Int): TextView? {
        str?.let {
            this?.append(it.typeSpan(0..it.length, type))
        }
        return this
    }
    
    /**
     *设置目标文字下划线
     * @return
     */
    fun TextView?.underlineSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.underlineSpan(range)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.underlineSpan(src.range(target!!))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendUnderlineSpan(str: String?): TextView? {
        str?.let {
            this?.append(it.underlineSpan(0..it.length))
        }
        return this
    }
    
    /**
     *设置目标文字删除线
     * @return
     */
    fun TextView?.strikethroughSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.strikethroughSpan(range)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.strikethroughSpan(src.range(target!!))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendStrikethroughSpan(str: String?): TextView? {
        str?.let {
            this?.append(it.strikethroughSpan(0..it.length))
        }
        return this
    }
    
    /**
     *设置目标文字颜色
     * @return
     */
    fun TextView?.foregroundColorIntSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.foregroundColorSpan(range, color)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.foregroundColorSpan(src.range(target!!), color)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendForegroundColorIntSpan(str: String?, color: Int): TextView? {
        str?.let {
            this?.append(it.foregroundColorSpan(0..it.length, color))
        }
        return this
    }
    
    /**
     *设置目标文字颜色
     * @return
     */
    fun TextView?.foregroundColorSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        @ColorRes color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.foregroundColorSpan(range, ResUtils.getColor(color))
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.foregroundColorSpan(src.range(target!!), ResUtils.getColor(color))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendForegroundColorSpan(str: String?, @ColorRes color: Int): TextView? {
        str?.let {
            this?.append(it.foregroundColorSpan(0..it.length, ResUtils.getColor(color)))
        }
        return this
    }
    
    /**
     *设置目标文字背景颜色
     * @return
     */
    fun TextView?.backgroundColorIntSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.backgroundColorSpan(range, color)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.backgroundColorSpan(src.range(target!!), color)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendBackgroundColorIntSpan(str: String?, color: Int): TextView? {
        str?.let {
            this?.append(it.backgroundColorSpan(0..it.length, color))
        }
        return this
    }
    
    /**
     *设置目标文字背景颜色
     * @return
     */
    fun TextView?.backgroundColorSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        @ColorRes color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.backgroundColorSpan(range, ResUtils.getColor(color))
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.backgroundColorSpan(src.range(target!!), ResUtils.getColor(color))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendBackgroundColorSpan(str: String?, @ColorRes color: Int): TextView? {
        str?.let {
            this?.append(it.backgroundColorSpan(0..it.length, ResUtils.getColor(color)))
        }
        return this
    }
    
    /**
     *设置目标文字引用线颜色
     * @return
     */
    fun TextView?.quoteColorIntSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.quoteColorSpan(range, color)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.quoteColorSpan(src.range(target!!), color)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendQuoteColorIntSpan(str: String?, color: Int): TextView? {
        str?.let {
            this?.append(it.quoteColorSpan(0..it.length, color))
        }
        return this
    }
    
    /**
     *设置目标文字引用线颜色
     * @return
     */
    fun TextView?.quoteColorSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        @ColorRes color: Int
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.quoteColorSpan(range, ResUtils.getColor(color))
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.quoteColorSpan(src.range(target!!), ResUtils.getColor(color))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendQuoteColorSpan(str: String?, @ColorRes color: Int): TextView? {
        str?.let {
            this?.append(it.quoteColorSpan(0..it.length, ResUtils.getColor(color)))
        }
        return this
    }
    
    /**
     *设置目标文字字体大小比例
     * @return
     */
    fun TextView?.proportionSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        proportion: Float
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.proportionSpan(range, proportion)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.proportionSpan(src.range(target!!), proportion)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendProportionSpan(str: String?, proportion: Float): TextView? {
        str?.let {
            this?.append(it.proportionSpan(0..it.length, proportion))
        }
        return this
    }
    
    /**
     *设置目标文字字体横向大小比例
     * @return
     */
    fun TextView?.proportionXSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        proportion: Float
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.proportionXSpan(range, proportion)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.proportionXSpan(src.range(target!!), proportion)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendProportionXSpan(str: String?, proportion: Float): TextView? {
        str?.let {
            this?.append(it.proportionXSpan(0..it.length, proportion))
        }
        return this
    }
    
    /**
     *设置目标文字字体上标
     * @return
     */
    fun TextView?.superscriptSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.superscriptSpan(range)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.superscriptSpan(src.range(target!!))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendSuperscriptSpan(str: String?): TextView? {
        str?.let {
            this?.append(it.superscriptSpan(0..it.length))
        }
        return this
    }
    
    /**
     *设置目标文字字体下标
     * @return
     */
    fun TextView?.subscriptSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.subscriptSpan(range)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.subscriptSpan(src.range(target!!))
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendSubscriptSpan(str: String?): TextView? {
        str?.let {
            this?.append(it.subscriptSpan(0..it.length))
        }
        return this
    }
    
    /**
     *设置目标文字字体
     * @return
     */
    fun TextView?.fontSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        font: String
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.fontSpan(range, font)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.fontSpan(src.range(target!!), font)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendFontSpan(str: String?, font: String): TextView? {
        str?.let {
            this?.append(it.fontSpan(0..it.length, font))
        }
        return this
    }
    
    /**
     *设置目标文字字体
     * @return
     */
    @RequiresApi(Build.VERSION_CODES.P)
    fun TextView?.fontSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        font: Typeface
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.fontSpan(range, font)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.fontSpan(src.range(target!!), font)
                this
            }
            else -> this
        }
    }
    
    @RequiresApi(Build.VERSION_CODES.P)
    fun TextView?.appendFontSpan(str: String?, font: Typeface): TextView? {
        str?.let {
            this?.append(it.fontSpan(0..it.length, font))
        }
        return this
    }
    
    /**
     *设置目标文字对齐方式
     * @return
     */
    fun TextView?.alignSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        align: Layout.Alignment
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                text = src.alignSpan(range, align)
                this
            }
            target.isNotNullOrEmpty() -> {
                text = src.alignSpan(src.range(target!!), align)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendAlignSpan(str: String?, align: Layout.Alignment): TextView? {
        str?.let {
            this?.append(it.alignSpan(0..it.length, align))
        }
        return this
    }
    
    /**
     *设置目标文字超链接
     * @return
     */
    fun TextView?.urlSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        url: String
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                movementMethod = LinkMovementMethod.getInstance()
                text = src.urlSpan(range, url)
                this
            }
            target.isNotNullOrEmpty() -> {
                movementMethod = LinkMovementMethod.getInstance()
                text = src.urlSpan(src.range(target!!), url)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendUrlSpan(str: String?, url: String): TextView? {
        str?.let {
            this?.append(it.urlSpan(0..it.length, url))
        }
        return this
    }
    
    /**
     *设置目标文字点击
     * @return
     */
    fun TextView?.clickIntSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        color: Int = Color.RED,
        isUnderlineText: Boolean = false,
        clickAction: () -> Unit
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                movementMethod = LinkMovementMethod.getInstance()
                highlightColor = Color.TRANSPARENT  // remove click bg color
                text = src.clickSpan(range, color, isUnderlineText, clickAction)
                this
            }
            target.isNotNullOrEmpty() -> {
                movementMethod = LinkMovementMethod.getInstance()
                highlightColor = Color.TRANSPARENT  // remove click bg color
                text = src.clickSpan(src.range(target!!), color, isUnderlineText, clickAction)
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendClickIntSpan(
        str: String?, color: Int = Color.RED,
        isUnderlineText: Boolean = false,
        clickAction: () -> Unit
    ): TextView? {
        str?.let {
            this?.append(it.clickSpan(0..it.length, color, isUnderlineText, clickAction))
        }
        return this
    }
    
    /**
     *设置目标文字点击
     * @return
     */
    fun TextView?.clickSpan(
        src: CharSequence? = this?.text,
        target: CharSequence? = this?.text,
        range: IntRange? = null,
        @ColorRes color: Int,
        isUnderlineText: Boolean = false,
        clickAction: () -> Unit
    ): TextView? {
        return when {
            this == null -> this
            src.isNullOrEmpty() -> this
            target.isNullOrEmpty() && range == null -> this
            range != null -> {
                movementMethod = LinkMovementMethod.getInstance()
                highlightColor = Color.TRANSPARENT  // remove click bg color
                text = src.clickSpan(range, ResUtils.getColor(color), isUnderlineText, clickAction)
                this
            }
            target.isNotNullOrEmpty() -> {
                movementMethod = LinkMovementMethod.getInstance()
                highlightColor = Color.TRANSPARENT  // remove click bg color
                text = src.clickSpan(
                    src.range(target!!),
                    ResUtils.getColor(color),
                    isUnderlineText,
                    clickAction
                )
                this
            }
            else -> this
        }
    }
    
    fun TextView?.appendClickSpan(
        str: String?,
        @ColorRes color: Int,
        isUnderlineText: Boolean = false,
        clickAction: () -> Unit
    ): TextView? {
        str?.let {
            this?.append(
                it.clickSpan(
                    0..it.length,
                    ResUtils.getColor(color),
                    isUnderlineText,
                    clickAction
                )
            )
        }
        return this
    }
    
    

    里面的ResUtils只是简单的获取资源文件,如果想直接引入,可以参考Github直接使用gradle依赖。

    相关文章

      网友评论

          本文标题:SpannableStringBuiler封装Kotlin

          本文链接:https://www.haomeiwen.com/subject/jdzfyltx.html