oynix

于无声处听惊雷,于无色处见繁花

使用HtmlCompat改变字体样式

这篇文章说一说Android中的HtmlCompat使用。

众所周知的是,要想做出各种炫酷多变样式的字体,使用Html+CSS最方便。一来是标签语法简单,二来是它支持设定很多属性。HtmlCompat这个类,就是帮助我们在Android中使用Html+CSS语法的工具。

介绍

HtmlCompatHtml的包装类,其中只有两个方法:一个是fromHtml,另个是toHtml

其实,所有带有Compat的类基本都是包装类。在Android SDK升级的过程中,到了某个版本某些类可能有了大改动,比如多了重载方法,这个版本以前的SDK,调用老方法;这个版本之后的调用新方法。而包装类的出现是为了方便调用者,我们只管调用包装类中的方法,而包装类里面会根据版本做出判断,去调用对应的方法。

  • fromHtml
    故名思义,这个方法就是把Html语法转换成要最终的样式,这个常用,这次主要说一说它

  • toHtml
    fromHtml相反,很少用,还没有遇到过这样的需求,就不说了

使用

1
2
3
4
5
6
public static Spanned fromHtml(@NonNull String source, @FromHtmlFlags int flags) {
if (Build.VERSION.SDK_INT >= 24) {
return Html.fromHtml(source, flags);
}
return Html.fromHtml(source);
}
  • param: source
    即Html文本,如”<b>Hello</b> World!”,标签b会将Hello加粗显示

  • param: flags
    一看便知,这个是SDK 24新加的参数,它的作用是添加一些额外的操作,它现在有9个可选的常量值,每个值都有介绍,比如:<p>标签会从新的一行开始、<h>标签会从新的一行开始,等等。一般不需要,传0即可

支持的标签

官方文档写的很简单,这是地址:文档。我是从源码中看的,Html.java文件中,有个handleStartTag方法,它支持以下的标签解析:

br, p, ul, li, div, span, strong, b, em, cite, dfn, i, big, small, font, blockquote, tt, a, u, del, s, strike, sup, sub, h, img

常用效果

  • 加粗
    b和strong都是加粗,效果是一样的,在解析的时候同等方式处理
    1
    2
    3
    private fun genBold() = HtmlCompat.fromHtml(
    "加粗效果:<b>加粗</b> or <strong>加粗2</strong>", 0
    )
  • 倾斜
    有多个标签都是倾斜:em、cite、dfn、i,它们的效果是一样的
    1
    2
    3
    private fun genItalic() = HtmlCompat.fromHtml(
    "倾斜效果: <i>倾斜</i> <em>倾斜</em> <cite>倾斜</cite>", 0
    )
  • 下划线
    1
    2
    3
    private fun genUnderline() = HtmlCompat.fromHtml(
    "下划线:<u>下划线</u>", 0
    )
  • 删除线
    1
    2
    3
    private fun genDelLine() = HtmlCompat.fromHtml(
    "删除线:<del>删除线</del>", 0
    )
  • 上角标
    1
    2
    3
    private fun genSup() = HtmlCompat.fromHtml(
    "上角标:2<sup>3</sup>", 0
    )
  • 下角标
    1
    2
    3
    private fun genSub() = HtmlCompat.fromHtml(
    "下角标:a<sup>4</sup>", 0
    )
  • 字体样式
    这里的font只支持两个属性,看过源码才知道,之前还一直研究为什么别的属性不生效。
    一个是color,一个是face。color用来改变字体颜色,face用来改变字体的样式,face用的少,color用的多。
    face有四个可选值:normal默认,sans无衬线字体,serif有衬线字体,monospace等宽字体。
    1
    2
    3
    4
    private fun genFont() = HtmlCompat.fromHtml(
    "字体样式:<font color='#873748' face='monospace'>字体颜色</font>," +
    "<font face='sans'>字体Face sans</font>", 0
    )

自定义标签

系统提供的标签就是这么多,如果需要一些其他的效果,如改变字体大小,可以自定义标签。HtmlCompat.fromHtml有个重载方法,是用来支持自定义标签的:

1
2
3
4
5
6
7
public static Spanned fromHtml(@NonNull String source, @FromHtmlFlags int flags,
@Nullable ImageGetter imageGetter, @Nullable TagHandler tagHandler) {
if (Build.VERSION.SDK_INT >= 24) {
return Html.fromHtml(source, flags, imageGetter, tagHandler);
}
return Html.fromHtml(source, imageGetter, tagHandler);
}

source和flags同上,如果使用了img标签,就要提供ImageGetter参数来获取图片,没用则传入null;如果使用了自定义标签,则需提供tagHandler来解析自定义的标签。

说一说自定义字体。

需要先创建一个类,实现TagHandler接口,接口里就一个方法,handleTag,是用来解析标签的,在这里添加逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// size是字号
class SizeLabel(private val size: Int) : Html.TagHandler {
// 记录开始的角标和结束的角标
private var startIndex = 0
private var stopIndex = 0

// 这个方法会被调用两次,开始标签调用一次,opening=true,结束标签调用一次,opening=false
// output就是实时解析出来的内容
override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader?) {
// tag就是标签的名字,这个名字不可与系统支持的重复,因为自定义的标签是放在判断的最后一个else里处理的
if (tag.lowercase(Locale.getDefault()) == "size") {
if (opening) {
startIndex = output.length
} else {
stopIndex = output.length
output.setSpan(
AbsoluteSizeSpan(size),
startIndex,
stopIndex,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}

}

使用的方式与上类似,如下:

1
2
3
private fun genSizeLabel() = HtmlCompat.fromHtml(
"自定义标签size:<size>加大字号</size>", 0, null, SizeLabel(50)
)

总结

总的来说,方式简单,用起来也很简单,可以满足一些基本的奇特UI需求。除了使用Html的方式,还有一些其他的方式,如在strings.xml文件中定义,也可以实现一些特殊的效果。

还可以使用Span来实现,这个的功能相当的多,在android.text.style这个包下都是它的实现类,每个类都可以实现一种UI效果,下次用到的时候再来仔细说一说。

附上示例的Github地址:https://github.com/oynix/htmlcompat-sample

------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2021/09/f6b0ced41fd6/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道