TextView解决字体大小无效之扩展Html自定义标签

MrLee 16天前 676 0
TextView的html内容显示开发者可能不陌生,但是想控制里面的字体大小,好像就不是这么简单了。那是怎么回事呢,请往下看!
String htmlStr = "<font color='#0000FF' size='50px'>我是蓝色的文本</font>
<font color='#ff0000' size='40px'>我是红色的文本</font>
<font color='#000000' size='29px'>我是黑色的文本</font>";

哈哈,这么简单的代码对于我们来说不就是分分钟就搞定吗,马上就来验证一下自己的成果

test

我擦,颜色出来了,但是字体大小怎么完全没改变,你是不是在逗我,凭我多年写Html的Hello World语句来说我的Html文本肯定没有错!,立马找一下原因是为什么,让我们来看看Html.fromHtml都做了什么事情。

test2

从源码里可以看到他会去定义一个SAX解析类Parser,然后传递到133行HtmlToSpannedConverter的构造方法里,并且调用这个类的conver()方法,那我们先看看这个类里面都做了什么

test

简单过一下构造方法,知道他都有什么

test4

如果有写过SAX解析的朋友现在肯定不会陌生,首先是去设置一个文档内容的处理器,进行XML的解析,里面就是一些头节点尾节点元素开头结束等等的XML相关处理,然后调用parser进行解析,然后会走回调方法,就列出我们比较关心的头尾方法

test

然后进行节点的处理

1

2

这时候眼睛比较凌厉的朋友已经发现我们最想要知道的代码了!他是如何去处理font这个标签的,让我们来看看这个方法startFont(mSpannableStringBuilder, attributes);

1

看到这里的时候我的心里是奔溃的。。尼玛这都什么跟什么,怎么就支持color这个标签,不支持size,还有这face是什么鬼,能支持face难道不能支持我传说中的大size么!!简直是在逗我!! 在这里我们可以看出来他的实现方式其实很简单,首先是使用XML去解析每一个节点,然后使用SpannableStringBuilder去进行拼接。
到了这个时候我们只能够自己去定义实现font以及获取里面的属性了,要怎么做呢,我们可以看到其实他在这一大堆if else的判断里面已经把font这个标签给处理掉了,不会给我们继续处理(不要跟我说修改源码),这时候其实我们看一下if else的最后,他是会进行回调到一个叫TagHandler里面的方法的,那么我们只需要去实现这个接口就可以了,从上面可以看出来,他是一个抽象类,用于给我们扩展的
上面说到了font标签已经被处理掉了,不会再回调给我们,所以我们就需要自己去定义一个标签,当然了,后端给予我们得一样可以是font的,我们只是自己去进行替换,类似这样子
htmlStr = htmlStr.replaceAll("font", "bluefont");
mTextView.setText(Html.fromHtml(htmlStr, null, new HtmlTagHandler()));

首先是替换成一个源码里不会进行处理的标签
/**
 * Created by blue.
 */
public class HtmlTagHandler implements Html.TagHandler {
    private static final String TAG_BLUE_FONT = "bluefont";
    private int startIndex = 0;
    private int stopIndex = 0;
    final HashMap<String, String> attributes = new HashMap<String, String>();
    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        processAttributes(xmlReader);
        if(tag.equalsIgnoreCase(TAG_BLUE_FONT)){
            if(opening){
                startFont(tag, output, xmlReader);
            }else{
                endFont(tag, output, xmlReader);
            }
        }
    }
    public void startFont(String tag, Editable output, XMLReader xmlReader) {
        startIndex = output.length();
    }
    public void endFont(String tag, Editable output, XMLReader xmlReader){
        stopIndex = output.length();
        String color = attributes.get("color");
        String size = attributes.get("size");
        size = size.split("px")[0];
if(!TextUtils.isEmpty(color) && !TextUtils.isEmpty(size)){
            output.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
        if(!TextUtils.isEmpty(size)){
            output.setSpan(new AbsoluteSizeSpan(Integer.parseInt(size)), startIndex, stopIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
    private void processAttributes(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) {
        }
    }
}

使用startIndex和stopIndex来进行判断每一个标签头和尾的位置,对里面的文本进行相对应的样式处理。然后让我们来运行一下代码试试

test

恩!?为什么第一行的样式不起效果呢??其实这个只是SAX解析的一些小bug而已,具体原理的话稍后我再贴上来,解决的方案也很简单: 1)在这一段Html格式的字符串前面再加上随意一个标签,例如<p>标签等等 2)发送html格式的字符串过来的时候将<html><body>也就是一整个网页需要的信息传递过来,也可以解决这个问题
那么修复了这个小bug后让我们来看看我们的最终成功,一个字段显示多种不同样式的文本

2



本文固定链接:http://www.ithtw.com/thread-12243.htm
转载请注明:MrLee 16天前 于 IT十万个为什么 发表
最新回复 (0)
回复
登录发表 or 还没有账号?去注册