首发于极光日报
探究在 TextView 中显示 HTML 的正确方法

探究在 TextView 中显示 HTML 的正确方法

简评:很惭愧,自己也曾经经常需要显示 HTML,但都没有深入理解过,基本都是试到能正确显示 HTML 为止。。。

首先,让我们看一看下面可能是在 TextView 中显示 HTML 的四种方式,您可以先判断下他们是否会正确的显示 HTML。

1. TextView#setText()

strings.xml:
<string name="what_the_html"><b>What</b> <i>the</i> <u>Html</u></string>

Activity.java:
textView.setText(R.string.what_the_html);

2. Resources#getString()

textView.setText(getString(R.string.what_the_html));

3. Html.fromHtml()

textView.setText(
  Html.fromHtml(
    getString(R.string.what_the_html)
  )
);

4. Html.fromHtml() + CDATA

strings.xml:
<string name="what_the_html">
  <![CDATA[
    <b>What</b> <i>the</i> <u>Html</u>
  ?]]>
</string>

Activity.java:
textView.setText(
  Html.fromHtml(
    getString(R.string.what_the_html)
  )
);

如果您没有判断对是 1 和 4 能正确显示 HTML,那么或许您需要继续阅读下面的内容。

Problem: String vs CharSequence

首先,我们要理解 TextView#setText() 方法接受的是一个 CharSequence 参数,而 Resources#getString() 返回的是一个 String。当然,String 和 CharSequence 这两个并不总是可以互换的。

而我们平时还是能往 setText() 中传递 String 的原因是 String 实现了 CharSequence。

还有一个同样实现了 CharSequence 的就是 Spanned,其支持使用被称为 "span" 的东西来修改文本的显示效果。Spans 是一组很小的对象,包含了有关如何绘制一段文本的信息,Android 系统中大量的用到了它。

一些常见的包括:

ps: 1. EditText 中闪烁的光标也是通过 span 实现的。 2. TextView 和 EditText 中的文本选中效果也是通过 span 实现的。

正确做法

当 HTML 需要被解析时,Android 同样会使用 span 来讲 HTML 标签转换为 TextView 可以理解并在屏幕上绘制的格式。为了做到这点,Android 提供了两个选项:

1. Resources#getText()

Resources#getText() 能解析到字符串中包含的 HTML 标记,并返回一个携带了样式的 CharSequence 对象。当 HTML 可以从 string 资源文件中直接得到时,这应该是我们首选的方式:

CharSequence styledText = getText(R.string.what_the_html);
textView.setText(styledText);

而 Resources#getString() 为什么错误,我们也可以通过看源代码来理解:

Resources.java:
public String getString(@StringRes int resId) {
  return getText(resId).toString();
}

可以看到其内部还是调用的 getText(),但 toString() 会抛弃掉所有的样式,String 是没有携带样式信息的。

2. Html.fromHtml()

Resources#getText() 内部其实还是使用了 Html.fromHtml() 来解析 HTML 标签的,也可以直接用于动态生成 HTML 的情况。Html.fromHtml() 的返回值同样也是一个 Spanned 对象。

Html.java:
public static Spanned fromHtml(String source) {
  ...
}

总结:当需要从资源文件中获取 html 并展示时,使用 Resource#getText() 而不是 Resource#getString()。当需要动态显示 HTML 时,使用 Html.fromHtml()。

原文:Android: Displaying HTML tags on TextView the right way

日报扩展阅读:

欢迎关注:知乎专栏「极光日报」,每天为 Makers 导读三篇优质英文文章。

编辑于 2017-07-12 23:08