美文网首页kotlin频道
Koltin优雅实现Spannablestring

Koltin优雅实现Spannablestring

作者: 747a945a4501 | 来源:发表于2016-08-16 10:48 被阅读512次

    目标


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

    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());
    
    我有密集恐惧症

    咱们既然用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<CharacterStyle>())
        val textConstructor = mutableListOf<String>(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

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