Android富文本显示

4,081 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

前言

在Android开发过程中,我们经常遇到显示多种风格的文本,比如部分加粗,部分变色,除了多个TextView拼接之外我们一般还有以下两种方式处理这类需求。

1.HtmlCompat

通过HtmlCompat.fromHtml()方法我们很容易实现变颜色,加粗字体等需求,它有两个参数,第一个是带样式的字符串,含有html标签,第二个参数是解析字符串的一些规则flag,主要有以下取值:

@IntDef(value = {
        FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH,
        FROM_HTML_SEPARATOR_LINE_BREAK_HEADING,
        FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM,
        FROM_HTML_SEPARATOR_LINE_BREAK_LIST,
        FROM_HTML_SEPARATOR_LINE_BREAK_DIV,
        FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE,
        FROM_HTML_OPTION_USE_CSS_COLORS,
        FROM_HTML_MODE_COMPACT,
        FROM_HTML_MODE_LEGACY
}, flag = true)
@RestrictTo(LIBRARY_GROUP_PREFIX)
@Retention(SOURCE)
@interface FromHtmlFlags {
}

FROM_HTML_SEPARATOR_LINE_BREAK_HEADING:h1-h6标签中的文本将与其他文本用一个换行符分隔 FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH自带换行

其他包含LINE_BREAK的flag也是处理各种标签换行的,比如li,ul等标签,下面将进行简单的使用

private fun formatSpanString(): Spanned {
    val htmlStr2 = ("<span>" +
            //大号字体-自带换行
            "<h3><font color='#000000'>春江花月夜</font></h3>" +
            //自带换行
            "<p><font color='#90EE90'>春江潮水连海平,海上明月共潮生。</font></p>" +
            //正常字体
            "<font color='#FF00FF'>滟滟随波千万里,何处春江无月明!</font><br>" +
            //加粗
            "<strong><font color='#3CB371'>江流宛转绕芳甸,月照花林皆似霰;</font></strong><br>" +
            //斜体
            "<em><font color='#FF4500'>空里流霜不觉飞,汀上白沙看不见。</font></em><br>" +
            //带有下划线
            "<u><font color='#8B4513'>江天一色无纤尘,皎皎空中孤月轮。</font></u><br>" +
            //加大字体
            "<big><font color='#800080'>江畔何人初见月?江月何年初照人?</font></big><br>" +
            "</span>")
    return HtmlCompat.fromHtml(htmlStr2, HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH)
}

运行效果如下

微信截图_20220413221246.png

2.SpannableString

SpannableString可以通过setSpan方法给字符串添加各种显示风格,而且非常方便指定设置的区间大小,在使用过程中如果要多次修改,一般使用SpannableStringBuilder。setSpan函数的原型为public void setSpan(Object what, int start, int end, int flags),其中what指定需要设置的样式,start和end为设置的区间,flag设置包不包含下标,有下面四种取值:

  • int SPAN_EXCLUSIVE_EXCLUSIVE = 33;不包含start和end
  • int SPAN_EXCLUSIVE_INCLUSIVE = 34;不包含start,包含end
  • int SPAN_INCLUSIVE_EXCLUSIVE = 17;包含start,不包含end
  • int SPAN_INCLUSIVE_INCLUSIVE = 18;包含start和end 常用的Span如下

ForegroundColorSpan

ForegroundColorSpan用来设置前景色,可以设置文字的颜色

val str = """
    春江潮水连海平,海上明月共潮生。
    滟滟随波千万里,何处春江无月明!
    江流宛转绕芳甸,月照花林皆似霰;
    空里流霜不觉飞,汀上白沙看不见。
    江天一色无纤尘,皎皎空中孤月轮。
    江畔何人初见月?江月何年初照人?
    
""".trimIndent()
val ssb = SpannableStringBuilder(str)
val colors = arrayListOf("#90EE90", "#FF00FF", "#3CB371", "#FF4500", "#8B4513", "#800080")
for (index in 0 until 6) {
    ssb.setSpan(
        ForegroundColorSpan( Color.parseColor(colors[index])),
        index*17,
        (index+1)*17,
        SPAN_EXCLUSIVE_EXCLUSIVE
    )
}

BackgroundColorSpan

BackgroundColorSpan可以用来设置背景色

ssb.setSpan(BackgroundColorSpan(Color.parseColor("#808080")), 0, 17, SPAN_EXCLUSIVE_EXCLUSIVE)

AbsoluteSizeSpan

AbsoluteSizeSpan用来设置文字大小

ssb.setSpan(AbsoluteSizeSpan(60), 17, 34, SPAN_EXCLUSIVE_EXCLUSIVE)

StrikethroughSpan

StrikethroughSpan用来设置删除线

ssb.setSpan(StrikethroughSpan(), 34, 51, SPAN_EXCLUSIVE_EXCLUSIVE)

UnderlineSpan

UnderlineSpan用来设置下划线

ssb.setSpan(UnderlineSpan(), 51, 68, SPAN_EXCLUSIVE_EXCLUSIVE)

ImageSpan

ImageSpan用来替换图片

//将诗句中的月替换为月亮图片
val drawable = ContextCompat.getDrawable(this, R.mipmap.moon)
drawable!!.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
val span = ImageSpan(drawable, ImageSpan.ALIGN_BASELINE)
ssb.setSpan(span, 81,82, SPAN_EXCLUSIVE_EXCLUSIVE)

ClickableSpan

ClickableSpan可以添加点击事件,使用ClickableSpan的时候必须为对应的TextView设置movementMethod

textView.movementMethod = LinkMovementMethod.getInstance()
ssb.setSpan(object :ClickableSpan(){
    override fun onClick(p0: View) {
        Toast.makeText(this@SpanActivity,"点击事件",Toast.LENGTH_LONG).show()
    }
}, 85, 101, SPAN_EXCLUSIVE_EXCLUSIVE)

以上设置效果图如下

Screenshot_20220413_231301.png