欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

解析在Android中为TextView增加自定义HTML标签的实现方法

程序员文章站 2023-11-23 23:52:52
android中的textview,本身就支持部分的html格式标签。这其中包括常用的字体大小颜色设置,文本链接等。使用起来也比较方便,只需要使用html类转换一下即可。比...

android中的textview,本身就支持部分的html格式标签。这其中包括常用的字体大小颜色设置,文本链接等。使用起来也比较方便,只需要使用html类转换一下即可。比如:

textview.settext(html.fromhtml(str));


然而,有一种场合,默认支持的标签可能不够用。比如,我们需要在textview中点击某种链接,返回到应用中的某个界面,而不仅仅是网络连接,如何实现?


经过几个小时对android中的html类源代码的研究,找到了解决办法,并且测试通过。

先看html类的源代码中有这样一段:

复制代码 代码如下:

/**
    * is notified when html tags are encountered that the parser does
    * not know how to interpret.
    */ 
   public static interface taghandler { 
       /**
        * this method will be called whenn the html parser encounters
        * a tag that it does not know how to interpret.
        */ 
       public void handletag(boolean opening, string tag, 
                                editable output, xmlreader xmlreader); 

这里定义了一个接口,接口用于什么呢?

再继续看代码,看到对html的tag进行解析部分的代码:

复制代码 代码如下:

private void handlestarttag(string tag, attributes attributes) { 
        if (tag.equalsignorecase("br")) { 
            // we don't need to handle this. tagsoup will ensure that there's a </br> for each <br>  
            // so we can safely emite the linebreaks when we handle the close tag.  
        } else if (tag.equalsignorecase("p")) { 
            handlep(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("div")) { 
            handlep(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("em")) { 
            start(mspannablestringbuilder, new bold()); 
        } else if (tag.equalsignorecase("b")) { 
            start(mspannablestringbuilder, new bold()); 
        } else if (tag.equalsignorecase("strong")) { 
            start(mspannablestringbuilder, new italic()); 
        } else if (tag.equalsignorecase("cite")) { 
            start(mspannablestringbuilder, new italic()); 
        } else if (tag.equalsignorecase("dfn")) { 
            start(mspannablestringbuilder, new italic()); 
        } else if (tag.equalsignorecase("i")) { 
            start(mspannablestringbuilder, new italic()); 
        } else if (tag.equalsignorecase("big")) { 
            start(mspannablestringbuilder, new big()); 
        } else if (tag.equalsignorecase("small")) { 
            start(mspannablestringbuilder, new small()); 
        } else if (tag.equalsignorecase("font")) { 
            startfont(mspannablestringbuilder, attributes); 
        } else if (tag.equalsignorecase("blockquote")) { 
            handlep(mspannablestringbuilder); 
            start(mspannablestringbuilder, new blockquote()); 
        } else if (tag.equalsignorecase("tt")) { 
            start(mspannablestringbuilder, new monospace()); 
        } else if (tag.equalsignorecase("a")) { 
            starta(mspannablestringbuilder, attributes); 
        } else if (tag.equalsignorecase("u")) { 
            start(mspannablestringbuilder, new underline()); 
        } else if (tag.equalsignorecase("sup")) { 
            start(mspannablestringbuilder, new super()); 
        } else if (tag.equalsignorecase("sub")) { 
            start(mspannablestringbuilder, new sub()); 
        } else if (tag.length() == 2 && 
                   character.tolowercase(tag.charat(0)) == 'h' && 
                   tag.charat(1) >= '1' && tag.charat(1) <= '6') { 
            handlep(mspannablestringbuilder); 
            start(mspannablestringbuilder, new header(tag.charat(1) - '1')); 
        } else if (tag.equalsignorecase("img")) { 
            startimg(mspannablestringbuilder, attributes, mimagegetter); 
        } else if (mtaghandler != null) { 
            mtaghandler.handletag(true, tag, mspannablestringbuilder, mreader); 
        } 
    } 

    private void handleendtag(string tag) { 
        if (tag.equalsignorecase("br")) { 
            handlebr(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("p")) { 
            handlep(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("div")) { 
            handlep(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("em")) { 
            end(mspannablestringbuilder, bold.class, new stylespan(typeface.bold)); 
        } else if (tag.equalsignorecase("b")) { 
            end(mspannablestringbuilder, bold.class, new stylespan(typeface.bold)); 
        } else if (tag.equalsignorecase("strong")) { 
            end(mspannablestringbuilder, italic.class, new stylespan(typeface.italic)); 
        } else if (tag.equalsignorecase("cite")) { 
            end(mspannablestringbuilder, italic.class, new stylespan(typeface.italic)); 
        } else if (tag.equalsignorecase("dfn")) { 
            end(mspannablestringbuilder, italic.class, new stylespan(typeface.italic)); 
        } else if (tag.equalsignorecase("i")) { 
            end(mspannablestringbuilder, italic.class, new stylespan(typeface.italic)); 
        } else if (tag.equalsignorecase("big")) { 
            end(mspannablestringbuilder, big.class, new relativesizespan(1.25f)); 
        } else if (tag.equalsignorecase("small")) { 
            end(mspannablestringbuilder, small.class, new relativesizespan(0.8f)); 
        } else if (tag.equalsignorecase("font")) { 
            endfont(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("blockquote")) { 
            handlep(mspannablestringbuilder); 
            end(mspannablestringbuilder, blockquote.class, new quotespan()); 
        } else if (tag.equalsignorecase("tt")) { 
            end(mspannablestringbuilder, monospace.class, 
                    new typefacespan("monospace")); 
        } else if (tag.equalsignorecase("a")) { 
            enda(mspannablestringbuilder); 
        } else if (tag.equalsignorecase("u")) { 
            end(mspannablestringbuilder, underline.class, new underlinespan()); 
        } else if (tag.equalsignorecase("sup")) { 
            end(mspannablestringbuilder, super.class, new superscriptspan()); 
        } else if (tag.equalsignorecase("sub")) { 
            end(mspannablestringbuilder, sub.class, new subscriptspan()); 
        } else if (tag.length() == 2 && 
                character.tolowercase(tag.charat(0)) == 'h' && 
                tag.charat(1) >= '1' && tag.charat(1) <= '6') { 
            handlep(mspannablestringbuilder); 
            endheader(mspannablestringbuilder); 
        } else if (mtaghandler != null) { 
            mtaghandler.handletag(false, tag, mspannablestringbuilder, mreader); 
        } 
    } 

可以看到,如果不是默认的标签,会调用mtaghandler的handletag方法。所以,我们可以实现此接口,来解析自己定义的标签类型。

再看一段我实现的对<game>标签进行解析的示例代码:

复制代码 代码如下:

public class gametaghandler implements taghandler { 
    private int startindex = 0; 
    private int stopindex = 0; 
    @override 
    public void handletag(boolean opening, string tag, editable output, 
            xmlreader xmlreader) { 
        if (tag.tolowercase().equals("game")) { 
            if (opening) { 
                startgame(tag, output, xmlreader); 
            } else { 
                endgame(tag, output, xmlreader); 
            } 
        }  

    } 
    public void startgame(string tag, editable output, xmlreader xmlreader) { 
        startindex = output.length(); 
    } 

    public void endgame(string tag, editable output, xmlreader xmlreader) { 
        stopindex = output.length(); 
        output.setspan(new gamespan(), startindex, stopindex, 
                    spanned.span_exclusive_exclusive); 
    } 

    private class gamespan extends clickablespan implements onclicklistener { 

        @override 
        public void onclick(view v) { 
            // 跳转某页面  
        } 
    }

上面这段代码,是对<game>…</game>的自定义标签进行解析。


具体调用方法:

       textview.settext(html.fromhtml(“点击<game>这里</game>跳转到游戏”,

              null, new gametaghandler()));

       textview.setclickable(true);

       textview.setmovementmethod(linkmovementmethod.getinstance());


运行后,能够看到文本中的字符串“这里”带了超链接,点击链接后,gamespan类的onclick()方法被调用。就可以在这个方法中进行跳转了。