由于项目需求需要实现一个TextView中含有不同大小不同颜色的文本,但TextView本身根本无法实现,出于写法的精简性我又不想另外多写几个TextView,所以打算采用HTML类中的fromHtml函数通过html标签解析实现。但由于Android对html标签支持不是太好,在将font标签中的size进行赋值后发现大小的设置并没有生效,随后我查看了源码,发现源码中并没有解析size属性,源码如下:
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));
}
}
由图中的源码得知,按照常规的html写法,以下这段代码中的size属性是不生效的。
String text = "<font color='red' size='50px'>" + "要显示的数据" + "</font>";
Spanned spanned = Html.fromHtml(text);
所以,我们需要使用TagHandler进行自定义标签来实现设置字体大小的功能。
首先自定义一个MyHtmlTagHandler,继承自HTML.TagHandler:
public class MyHtmlTagHandler implements Html.TagHandler {
private String tagName;
private int startIndex = 0;
private int endIndex = 0;
final HashMap<String, String> attributes = new HashMap<>();
public MyHtmlTagHandler(String tagName) {
this.tagName = tagName;
}
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
// 判断是否是当前需要的tag
if (tag.equalsIgnoreCase(tagName)) {
// 解析所有属性值
parseAttributes(xmlReader);
if (opening) {
startHandleTag(tag, output, xmlReader);
} else {
endEndHandleTag(tag, output, xmlReader);
}
}
}
public void startHandleTag(String tag, Editable output, XMLReader xmlReader) {
startIndex = output.length();
}
public void endEndHandleTag(String tag, Editable output, XMLReader xmlReader) {
endIndex = output.length();
// 获取属性值
String color = attributes.get("color");
String size = attributes.get("size");
size = size.split("px")[0];
// 设置字体大小
if (!TextUtils.isEmpty(size)) {
output.setSpan(new AbsoluteSizeSpan(Integer.parseInt(size)), startIndex, endIndex,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// 设置颜色
if (!TextUtils.isEmpty(color)) {
output.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, endIndex,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
/**
* 解析所有属性值
*
* @param xmlReader
*/
private void parseAttributes(final XMLReader xmlReader) {
try {
Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
elementField.setAccessible(true);
Object element = elementField.get(xmlReader);
Field attsField = element.getClass().getDeclaredField("theAtts");
attsField.setAccessible(true);
Object atts = attsField.get(element);
Field dataField = atts.getClass().getDeclaredField("data");
dataField.setAccessible(true);
String[] data = (String[]) dataField.get(atts);
Field lengthField = atts.getClass().getDeclaredField("length");
lengthField.setAccessible(true);
int len = (Integer) lengthField.get(atts);
for (int i = 0; i < len; i++) {
attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
}
} catch (Exception e) {
}
}
}
接下来的使用(我这里采取了两个字符串入参的文字风格设置):
public static android.text.Spanned colorString(String str1,String str1FontColor,String str1FontSize,String str2,String str2FontColor,String str2FontSize) {
try {
String text = "<br/><myfont color='" + str1FontColor + "' size='" + str1FontSize + "'>" + str1 + "</myfont>"
+ "<myfont color='" + str2FontColor + "' size='" + str2FontSize + "'>" + str2 + "</myfont>";
Spanned spanned = Html.fromHtml(text, null, new MyHtmlTagHandler("myfont"));
return spanned;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
接着将生成的Spanned对象放入TextView的setText函数即可。
PS:如果不在HTML标签最前面加入其他HTML元素,此函数可能不会生效,原因未知。
网友评论