Android 开发中经常会有对 TextView
的局部文字样式做单独处理的需求,比如针对某些文字进行加粗或是改变颜色等等。
这种处理在 Web 开发中十分简单,HTML 的标签能够很方便的进行调整。但是在 Android 开发中,却要稍微麻烦一些,我们来看几种处理方式。
多 TextView
拼接
利用多个 TextView
拼接的方式,我们可以针对不同的 TextView
样式进行调整,这种方法似乎跟 HTML 标签有点类似,但实际上却相去甚远。
当你有多个不连续的文字需要使用同一种样式的时候,你就需要建立多个具有相同样式的 TextView
,从而对同一个句子或段落形成割裂感。
另一方面,你甚至还需要处理好每一个 TextView
的 Padding 以及 Margin 边距属性以及适当的换行等,否则 UI 就会乱得惨不忍睹。
总体来说,多 TextView
拼接来处理同一段文字是非常不推荐的方法。
利用 HTML 标签设置样式
既然 HTML 在处理这种需求有极大的优势,那么我们能不能使用类似的处理方式呢?
Android SDK 中其实为我们提供了直接解析 HTML 的方法,所以只要将字符串包装成 HTML 代码即可实现局部样式修改,比如:
TextView textView = findViewById(R.id.sign_up_link);
textView.setText(Html.fromHtml("No account yet? <font color='#FFFFFF'><big>Create one</big></font>."));
利用 Html.fromHtml()
方法可以将字符串解析成 HTML 样式,再像平时一样使用的 setText()
方法即可把文字加载到 TextView
中去。
效果如下:
可以看到,底部的那行小字对后半句做了加粗以及颜色调整。
利用 HTML 设置样式十分方便,解决了多 TextView
拼接的割裂感,但它依然存在问题。
你可以看到我的示例代码中使用了 <big>
标签来设置字体的大小,其实在常规的 HTML 代码中,我更加倾向于使用 <font>
标签的 size
属性来进行调整,因为可以减少标签嵌套。
但是我在这里使用 <big>
标签的原因是,Html.fromHtml()
方法无法解析 size
属性,我们可以看看源码:
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
handleStartTag(localName, attributes);
}
private void handleStartTag(String tag, Attributes attributes) {
if (...) {
...
} else if (...) {
...
} else if (tag.equalsIgnoreCase("font")) {
startFont(mSpannableStringBuilder, attributes);
} else if (...) {
...
}
}
private void startFont(Editable text, Attributes attributes) {
String color = attributes.getValue("", "color");
String face = attributes.getValue("", "face");
if (!TextUtils.isEmpty(color)) {
int c = getHtmlColor(color);
if (c != -1) {
start(text, new Foreground(c | 0xFF000000));
}
}
if (!TextUtils.isEmpty(face)) {
start(text, new Font(face));
}
}
可以看到,对于 <font>
标签,只解析 color
和 face
两个属性,其他属性比如刚提到的 size
并没有进行解析,自然也就不可以通过其设置字体大小了。
这里仅仅拿了 <font>
标签进行举例,其他标签也有类似的情况,也就是说 Android 的 Html.fromHtml()
方法并没有办法对所有的 HTML 样式进行解析。
利用 SpannableString
设置样式
其实 Android SDK 也为我们提供了修改 TextView
局部样式的方法,利用 SpannableString
也可以实现类似的功能:
SpannableString spannableString = new SpannableString("Hello World!");
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.RED);
spannableString.setSpan(backgroundColorSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView textView = findViewById(R.id.tv);
textView.setText(spannableString);
这是 TextView
的 Span 样式类,首先在 SpannableString
对象中传入要显示的内容,调用 setSpan()
方法实现字符串各种风格的显示。
setSpan()
方法有 4 个参数。第一个参数表示格式,可以是前景色、背景色等,这里指定其背景色为红色;第二个参数是格式开始的 Index;第三个参数是格式结束的 Index;第四个参数是一个常量,有以下 4 个值:
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
:前面包括,后面不包括。即在文本前插入新文本会应用该样式,而在文本后插入新文本不会应用该样式。Spannable.SPAN_INCLUSIVE_INCLUSIVE
:前面包括,后面包括。即在文本前插入新文本会应用该样式,在文本后插入新文本也会应用该样式。Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
:前面不包括,后面不包括。即在文本前插入新文本不会应用该样式,在文本后插入新文本也不会应用该样式。Spannable.SPAN_EXCLUSIVE_INCLUSIVE
:前面不包括,后面包括。即在文本前插入新文本不会应用该样式,而在文本后插入新文本会应用该样式。
最后也是调用 TextView
的 setText()
方法把这个 SpannableString
对象设置进去,效果如下:
使用 SpannableString
不仅可以设置局部样式,还支持设置局部点击事件,这点比利用 HTML 标签设置样式更加灵活。