Koltin优雅实现Spannablestring

目标


平时要实现如下的效果,需要用Spannablestring。

Koltin优雅实现Spannablestring_第1张图片
Paste_Image.png

但是代码写的老长了,还要算坐标,还需要记住各种效果对应的CharacterStyle子类,代码如下:

SpannableString spanText = new SpannableString("特殊效果的字符串");
SpanspanText.setSpan(new TypefaceSpan("monospace"), 3, 10,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
SpanspanText.setSpan(CharacterStyle子类(),下标,下标,区间方式)
mTVText.append(spanText);
mTVText.setMovementMethod(new LinkMovementMethod());
Koltin优雅实现Spannablestring_第2张图片
我有密集恐惧症

咱们既然用kotlin写,肯定希望用它的语法糖把这段代码优雅的实现,咱们实现的效果如下,当然可能还有更简洁的实现方式。

setText("前景色".style { foregroundColor(Color.RED) }
        + "背景色".style { backgroundColor(Color.BLUE) }
        + "删除线".style { strikethrough() }
        + "下划线".style { underline() }
        + "设置图片".style { dynamicDrawable(resources.getDrawable(R.drawable.icon_address),true) }
        + "大号的字体".style { absoluteSize(DimensAdapter.textPxSize(CustomTSDimens.BIG).toInt()) }
        + "2倍的字体".style { relativeSize(2f) }
        + "粗体".style { style(Typeface.BOLD) }
        + "x抽缩放3倍".style { scaleX(3f) }
        + "图片图片".style { image(resources.getDrawable(R.drawable.icon_user)) }
        + "我是下标".style { subscript() }
        + "我是上标".style { superscript() }
        + "http://www.baidu.com".style { url("http://www.baidu.com") })

实现方式


定义一个实体类(TextSpan)记录样式的信息(直接贴代码)

class TextSpan(val content: String) {
    //所有样式
    val styles = mutableListOf(mutableListOf())
    val textConstructor = mutableListOf(content)
//    var startIndex = 0
 //        private set(value) {
//            field = value
//            endIndex = value + content.length
//        }
//    var endIndex = 0
//        private set
    fun backgroundColor(colorVal: Int) {
        styles[0].add(BackgroundColorSpan(colorVal))
    }

    fun foregroundColor(colorVal: Int) {
        styles[0].add(ForegroundColorSpan(colorVal))
    }
    /**
     * 模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter) BlurMaskFilter
     */
    fun maskFilter(maskFilter: MaskFilter) {
        styles[0].add(MaskFilterSpan(maskFilter))
    }

    /** 
    * 光栅效果 StrikethroughSpan()
     */
    fun rasterizer(rasterizer: Rasterizer) { 
       styles[0].add(RasterizerSpan(rasterizer))
    } 
   /**
     * 删除线(中划线)
     */
    fun strikethrough() {
        styles[0].add(StrikethroughSpan())
    }
    /**     * 下划线     */
    fun underline() {
        styles[0].add(UnderlineSpan())
    }
    /**
     * 设置图片 (DynamicDrawableSpan.ALIGN_BASELINE  or DynamicDrawableSpan.ALIGN_BOTTOM)
     */
    fun dynamicDrawable(drawable: Drawable, isAlignBaseLine: Boolean) {
        styles[0].add(object : DynamicDrawableSpan(if (isAlignBaseLine) DynamicDrawableSpan.ALIGN_BASELINE else DynamicDrawableSpan.ALIGN_BOTTOM) {
            override fun getDrawable(): Drawable {
                drawable.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight)
                return drawable
            }
        })
    }

    /**
     * 字体大小(像素) 
    */
    fun absoluteSize(textSize: Int) { 
       styles[0].add(AbsoluteSizeSpan(textSize, false))
    }

    /**     * 图片     */
    fun image(drawable: Drawable, width: Int = drawable.minimumWidth, height: Int = drawable.minimumHeight) { 
       drawable.setBounds(0, 0, width, height)  
      styles[0].add(ImageSpan(drawable))
    }

    /**
     * ScaleXSpan 基于x轴缩放 
    */
    fun scaleX(scaleRate: Float) {
        styles[0].add(ScaleXSpan(scaleRate))
    } 

   /**
     *  相对大小(文本字体)
     */
    fun relativeSize(scanRate: Float) {
        styles[0].add(RelativeSizeSpan(scanRate))
    }

    /** 
    *  字体样式:粗体、斜体等 Typeface
     */
    fun style(typeface: Int) {
        styles[0].add(StyleSpan(typeface))
    }

    /**     * 下标(数学公式会用到)     */
    fun subscript() {
        styles[0].add(SubscriptSpan()) 
   } 

   /**     * 上标(数学公式会用到)     */
    fun superscript() {
        styles[0].add(SuperscriptSpan()) 
   } 

   /**     *  文本字体     */
    fun typeface(typeface: String) {  
      styles[0].add(TypefaceSpan(typeface))
    } 

   /**     * 文本超链接     */
    fun url(linkAddress: String) {
        styles[0].add(URLSpan(linkAddress))
    }
  }

实现+的算法,用到运算符重载

operator fun plus(nextVal: TextSpan): TextSpan {
     styles.addAll(nextVal.styles)
     textConstructor.addAll(nextVal.textConstructor)
     return this
}

最后TextView.setText(TextSpan) 可以用,需要给TextView扩展一个方法
(ps:我这里面是2个循环不是很好,可能还有更好的办法去做)

fun TextView.setText(textSpan: TextSpan) {
    val builder = StringBuilder()
    textSpan.textConstructor.forEach{
        builder.append(it)
    }

    val spanStr = SpannableString(builder.toString())
    var index = 0
    textSpan.textConstructor.forEachIndexed { position, str ->
        val end = index + str.length
        textSpan.styles[position].forEach { 
           spanStr.setSpan(it, index, end,Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
           if(it is URLSpan) this.movementMethod = LinkMovementMethod()
        }
        index+= str.length
    }
        text = spanStr
}

这样就大功告成了.

你可能感兴趣的:(Koltin优雅实现Spannablestring)