Android中为TextView增加自定义的HTML标签

Stella981
• 阅读 549

 

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方法。所以,我们可以实现此接口,来解析自己定义的标签类型。

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

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) {
            // 跳转某页面
        }
    }

 

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

具体调用方法:

       textView.setText(Html.fromHtml(“点击这里跳转到游戏”,

              null, new GameTagHandler()));

       textView.setClickable(true);

       textView.setMovementMethod(LinkMovementMethod.getInstance());

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

$(document).ready(function(){dp.SyntaxHighlighter.HighlightAll('code');});
原文链接: http://blog.csdn.net/arui319/article/details/6709424

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
2年前
jango Form表单组件
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。Djangoform组件就实
Stella981 Stella981
2年前
50 Android Hack 读书笔记
1、可以指定android:weightSum属性2、使用include标签来应对变化3、使用ViewStub标签延迟加载有可能不需要加载的数据标签中可以指定inflateId属性4、使用自定义ViewGroup,重写onMeasure、onLayout5、使用Android的PreferenceCategory6、使用TextSwitcher
Stella981 Stella981
2年前
HTML 使用CSS 设置透明度Opacity
HTML/CSS标签透明度效果的实现在HTMLCSS编程中,实现半透明背景,通常有3中做法,分别是使用RGBA,PNG和CSSfilter。方法一.第一种是HTML5的透明,在H5中支持透明背景颜色,但遗憾的是,H5中的办透明背景颜色只支持rgba的写法,不支持16进制的写法如:ba
Stella981 Stella981
2年前
ClickableSpan造成Listview的OnItemClickListener失效的解决办法
一、前提和解决做了个界面,在listview的itemview里要@,要超链接,要话题跳转等等等。用ClickableSpan实现了textview的点击跳转,之后发现listview的OnItemClickListener不响应,给textview的focusable设置为false,或者listview的descendantFocusabi
Stella981 Stella981
2年前
HTML5 audio 如何实现播放多个MP3音频
<audio标签是HTML5中的新标签,定义声音用于嵌入音频内容,比如音乐或其他音频流。用的比较多音频格式是.mp3。<audio标签常用属性如下表属性值描述autoplayautoplay添加该属性后,音频会自动播放controlscontrols设置后,显示控件,如播放按钮、音量looploop添加
Wesley13 Wesley13
2年前
HTML基础知识(常见元素、列表、链接元素、图片元素)
1、HTML有关概念全称:HyperTextMarkupLanguage(超文本标记语言)其文件扩展名为“.html”或“.htm”    \超文本在普通的文本基础上,添加超链接、图片、音频或视频等    \标记标记就是HTML中的标签(元素),特点:<a\语言目前目标所能识别的版本:
Easter79 Easter79
2年前
SVG之文本
一、文本标签<text  SVG支持直接对文本进行操作,如果我们需要在SVG中使用文本,那么我们需要使用到<text标签。直接看一个简单的demo。1<!DOCTYPEhtml2<html3<head4<meta
Stella981 Stella981
2年前
HTML中meta标签的作用与使用
META标签用来描述一个HTML网页文档的属性META标签可分为两大部分:HTTPEQUIV和NAME变量。HTTP实例HTML代码实例中有一项内容是<metahttpequiv"ContentType"content"text/html;charsetgb2312"其作用是指定了当前文档所使用的字符编码为gb2
Stella981 Stella981
2年前
SVG之文本
一、文本标签<text  SVG支持直接对文本进行操作,如果我们需要在SVG中使用文本,那么我们需要使用到<text标签。直接看一个简单的demo。1<!DOCTYPEhtml2<html3<head4<meta
稚然 稚然
3个月前
2023最新尚硅谷前端开发html5+css3零基础视频课程
//下仔のke:https://yeziit.cn/14334/HTML(超文本标记语言)是一种用于创建网页的标准标记语言。它被用于定义网页的结构和内容,并且是构成网页的基础。HTML使用标签来描述网页中的元素,例如标题、段落、链接、图片等。一个基本的HT