TextView使用(二)、spannablestring和spannablestringbuilder的使用,实现文字高亮、可点击

696

TextView除了自身的简单文字展示之外,是可以使用Spanned Html实现很多个性化的功能的,比如一段文字使用中部分文字颜色高亮、支持点击事件。就可以使用Spanned的方式实现。

SpannableString一个最基本的用来封装Spanned的封装类,可以用来使用setSpan增加不同的span状态。

spannableString.setSpan(
    ClickSpan(it.content, it.color, it.clickEvent),
    0, spannableString.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

SpannableStringBuilder可以用来包装多个SpannableString对象,构造出来一个新的支持Spanned方式的CharSequence文字对象。

spannableStringBuilder.append(spannableString)

TextView中常见的Spanned操作类:

  • ForegroundColorSpan 文字前景颜色
  • BackgroundColorSpan 文字背景色
  • ClickableSpan 文字可点击、有点击事件
  • BlurMaskFilter 模糊效果
  • StrikethroughSpan 删除线效果
  • UnderlineSpan 下划线效果
  • AbsoluteSizeSpan 字体绝对大小
  • RelativeSizeSpan 字体相对大小
  • ScaleXSpan 基于x的缩放
  • StyleSpan 字体模式、粗体、斜体
  • TextAppearanceSpan 字体大小、样式、颜色
  • TypefaceSpan 文字字体
  • URLSpan 文本超链接
  • SubscriptSpan 小标
fun TextView.setSpannableText(spanList: MutableList<SpanEntity>) {
    val spannableStringBuilder = SpannableStringBuilder()
    var isClickable = false
    spanList.forEach {
        val spannableString = SpannableString(it.content)
        if (it.clickable) {
            spannableString.setSpan(
                ClickSpan(it.content, it.color, it.clickEvent),
                0, spannableString.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
            isClickable = true
        } else {
            spannableString.setSpan(
                ForegroundColorSpan(it.color),
                0, spannableString.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
        spannableString.setSpan(
            StyleSpan(it.typeface), 0,
            spannableString.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
        )
        spannableStringBuilder.append(spannableString)
    }
    this.text = spannableStringBuilder
    if (isClickable) {
        this.highlightColor = Color.TRANSPARENT
        this.setHintTextColor(Color.TRANSPARENT)
        this.movementMethod = LinkMovementMethod.getInstance()
    }
}

class ClickSpan(val content: String, val color: Int, val click: (content: String) -> Unit) :
    ClickableSpan() {
    override fun onClick(widget: View) {
        click.invoke(content)
    }

    override fun updateDrawState(ds: TextPaint) {
        ds.color = color
        ds.isUnderlineText = false
    }
}

data class SpanEntity(
    var color: Int,
    var content: String,
    val typeface: Int = Typeface.NORMAL,
    var clickable: Boolean = false,
    var clickEvent: (content: String) -> Unit = {}
)

使用方式

tvSize20.setSpannableText(
    arrayListOf(
        SpanEntity(
            // 文字颜色
            color = Color.parseColor("#F14400"),
            // 文字内容
            content = "我的内容",
            // 文字样式
            typeface = Typeface.BOLD,
            // 文字是否支持点击
            clickable = true,
            // 文字点击事件
            clickEvent = {}
        )
        ...
    )
)