整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Android TextView实现富文本

Android TextView实现富文本

extView富文本显示主要有两种方式,一个是使用SpannableString类,另一种是直接将富文本写成HTML形式。

SpannableString

SpannableString是Android内置的专门处理富文本的类,基本涵盖了你能想到的所有富文本表示,字体、颜色、图片、点击事件等

//设置Hello World前三个字符为红色,背景为蓝色
SpannableString textSpanned1=new SpannableString("Hello World");
textSpanned1.setSpan(new ForegroundColorSpan(Color.RED),
        0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textSpanned1.setSpan(new BackgroundColorSpan(Color.BLUE),
        0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text1.setText(textSpanned1);

//设置Hello World前三个字符字体为斜体
SpannableString textSpanned2=new SpannableString("Hello World");
textSpanned2.setSpan(new StyleSpan(Typeface.ITALIC),
        0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text2.setText(textSpanned2);

//设置Hello World前三个字符有下划线
SpannableString textSpanned3=new SpannableString("Hello World");
textSpanned3.setSpan(new UnderlineSpan(),
        0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text3.setText(textSpanned3);

//设置Hello World前三个字符有点击事件
SpannableStringBuilder textSpanned4=new SpannableStringBuilder("Hello World");
ClickableSpan clickableSpan=new ClickableSpan() {
    @Override
    public void onClick(View view) {
        Toast.makeText(MainActivity.this, "Hello World", Toast.LENGTH_SHORT).show();
    }
};
textSpanned4.setSpan(clickableSpan,
        0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//注意:此时必须加这一句,不然点击事件不会生效
text4.setMovementMethod(LinkMovementMethod.getInstance());
text4.setText(textSpanned4);

setSpan()

void setSpan (Object what, int start, int end, int flags)

参数

说明

what

样式

start

样式开始的字符索引

end

样式结束的字符索引

flags

新插入字符的设置

flags:

取值

说明

Spanned.SPAN_EXCLUSIVE_EXCLUSIVE

前后都不包括

Spanned.SPAN_EXCLUSIVE_INCLUSIVE

前面不包括,后面包括

Spanned.SPAN_INCLUSIVE_EXCLUSIVE

前面包括,后面不包括

Spanned.SPAN_INCLUSIVE_INCLUSIVE

前后都包括

这个flags可能有人不懂,它表示了这个样式是否作用在本字符串之前或之后插入的其他字符串上

SpannableStringBuilder textSpannedBuilder1=new SpannableStringBuilder();
SpannableString textSpanned11=new SpannableString("Hello");
textSpanned11.setSpan(new BackgroundColorSpan(Color.BLUE), 0, textSpanned11.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableString textSpanned12=new SpannableString("World");
text1.setText(textSpannedBuilder1.append(textSpanned11).append(textSpanned12));

SpannableStringBuilder textSpannedBuilder2=new SpannableStringBuilder();
SpannableString textSpanned21=new SpannableString("Hello");
textSpanned21.setSpan(new BackgroundColorSpan(Color.BLUE), 0, textSpanned21.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
SpannableString textSpanned22=new SpannableString("World");
text2.setText(textSpannedBuilder2.append(textSpanned21).append(textSpanned22));

SpannableStringBuilder textSpannedBuilder3=new SpannableStringBuilder();
SpannableString textSpanned31=new SpannableString("Hello");
textSpanned31.setSpan(new BackgroundColorSpan(Color.BLUE), 0, textSpanned21.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
SpannableString textSpanned32=new SpannableString("World");
textSpanned32.setSpan(new BackgroundColorSpan(Color.GREEN), 0, 3, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
text3.setText(textSpannedBuilder3.append(textSpanned31).append(textSpanned32));

text1里,"Hello"的flags是SPAN_EXCLUSIVE_EXCLUSIVE,在它之后插入的"World"显示正常,无背景。

  • text2里,"Hello"的flags是SPAN_EXCLUSIVE_INCLUSIVE,它之后插入的"World"的背景变为蓝色。
  • 需要注意的是text3,这里的"Hello"与text2相同,而"World"的一部分字符设置为绿色,显然这部分字符显示的是绿色,这说明虽然设置了SPAN_EXCLUSIVE_INCLUSIVE属性,但只要后面的字符串设置了同类的样式,还是覆盖掉flags属性。
  • HTML

    接下来介绍HTML的用法,其实HTML使用起来要比SpannableString简洁,我们只需要按照平时写HTML的习惯,将需要显示的富文本加上各种标签,就可以显示在TextView上了,下面我们看一下例子:

    String htmlText1="<b>Hello World</b>";
    text1.setText(Html.fromHtml(htmlText1));
    
    String htmlText2="<font color='#ff0000'>Hello World</font>";
    text2.setText(Html.fromHtml(htmlText2));
    
    String htmlText3="<i><a href='https://gavinli369.github.io/'>我的博客</a></i>";
    text3.setMovementMethod(LinkMovementMethod.getInstance());
    text3.setText(Html.fromHtml(htmlText3));

    TextView支持的HTML标签

    标签

    说明

    font

    设置字体和颜色

    big

    大号字体

    small

    小号字体

    i

    斜体

    b

    粗体

    tt

    等宽字体

    br

    换行(行与行之间没有空行)

    p

    换行(行与行之间有空行)

    a

    链接

    img

    图像

    ndroid 中的 TextView 组件常用于显示文本内容,其实它也可以显示 HTML 的内容。简单来讲,这就需要先把 HTML 的内容以字符串的形式获取后,经过 android.text.Html.fromHtml()转化成 Spanned 的格式,然后将其传递到 TextView 的 setText()方法中,这样就可以在 TextView 中显示 HTML 页面的内容了。需要注意的是,并不是所有的 HTML 标签在 TextView 中都是支持的,且官方文档并没有明确的说明支持 HTML 标签列表,通过查看 Android 源代码,可以得到简单的支持列表。

    {<br>,< p>,< div align=>,< strong>, <b>, <em>, <cite>, <dfn>, <i>, <big>, <small>, <font size=>,  <font color=>, <blockquote>, <tt>, <a href=>, <u>, <sup>, <sub>, <h1>,<h2>,<h3>,<h4>,<h5>,<h6>, <img src=>, <strike>}
    1

    下面的示例来介绍如何在 TextView 中显示一段 HTML 内容,要显示的这段 HTML 内容即包含超链接内容,也包含有图片。
    在 TextView 中显示 HTML 内容

    显示的过程中最主要的过程就是调用 Android.text.Html 类提供的 fromHtml()方法,将一段 HTML 内容转化为 Spanned 对象。

    Android.text.Html 类提供的 fromHtml()方法使用如下清单 4
    fromHtml()方法定义

    public static Spanned fromHtml(String source, ImageGetter imageGetter,
        TagHandler tagHandler) {
            ……
    HtmlToSpannedConverter converter=new HtmlToSpannedConverter(source, imageGetter, tagHandler,  parser);
    return converter.convert();
    }
    1234567

    source,就是包含 HTML 内容的字符串。而 Html.ImageGetter 和 Html.TagHandler 是两个接口,提供给开发者继承使用。
    imageGetter, 如果要显示图片是需要被继承的,重写 getDrawable(String source)方法,用于获取 HTML 里面的图片来显示在 TextView 中。
    tagHandler,其作用是把 HTML 带标记的文本内容字符串转化成可以显示效果的的 Spanned 字符串 。由于并非所有的 HTML 标签都可以转化,所以在使用时,用户需要自己添加一些必要的标签和处理方法时才会继承使用的。

    在本例中使用 fromHtml()方法之前,要准备好该方法要用的三个参数内容,首先将 HTML 字符串内容准备好,在项目中需要创建两个类 MImageGetter 和 MTagHandler 分别继承于 ImageGetter 和 TagHandler,分别用户图片的获取,和特殊标签的支持。
    MImageGetter

    继承于 ImageGetter,重写 getDrawable (String source) 方法中从 assets 路径下取出的图片流(这里当然也可以通过网络操作来完成图片流的获取),最后获得可供显示的图片对象,例如 Drawable 对像。由于 Android 设备的异构性,为了有更好的显示效果,通常需要获取屏幕大小,然后调用 drawable.setBounds () 还可以重新设置图片的大小, 最后返回合适大小的图片 Drawable 对象。 由此 Spanned 中的 ImageSpan 就获得了图像被显示在 TextView 中对应位置了。

    TypedValue typedValue=new TypedValue();
    typedValue.density=TypedValue.DENSITY_DEFAULT;
    drawable=Drawable.createFromResourceStream(null, typedValue, is, "src");
    DisplayMetrics dm=c.getResources().getDisplayMetrics();  
    int dwidth=dm.widthPixels-10;//padding left + padding right
    float dheight=(float)drawable.getIntrinsicHeight()*(float)dwidth/(float)drawable.getIntrinsicWidth();
    int dh=(int)(dheight+0.5);
    int wid=dwidth;
    int hei=dh;
    drawable.setBounds(0, 0, wid, hei);DisplayMetrics dm=c.getResources().getDisplayMetrics();
    12345678910

    MTagHandler

    继承于 TagHandler,重写了 handleTag()方法,为的是支持部分标签,这四个标签是在 formHtml()方法中本身是不支持。如果开发者认为安卓 TagHandler 提供的默认标签解析已经够用,直接在 fromHtml()方法中第三个参数的地方填写 null 既可。
    重写 handleTag()方法

    public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
    if (tag.equals("ul") || tag.equals("ol") || tag.equals("dd")) {
        if (opening) {
        mListParents.add(tag);
        } else mListParents.remove(tag);
    } else if (tag.equals("li") && !opening) {
         handleListTag(output);
    }
    }
    private void handleListTag(Editable output) {
    ……
     }
    123456789101112

    最后,在完成了 MImageGetter、MTagHandler 以后,就可以通过 formHtml()方法将 HTML 内容转化为可供显示的 SpannableString,将 SpannableString 通过 setText 方法放入 TextView 中,就可以显示图文并茂的内容了。

    progressBar.setVisibility(View.GONE);
    text.setText(Html.fromHtml(htmlCont, new MImageGetter(text,MainActivity.this), new MTagHandler()));
    text.setVisibility(View.VISIBLE);
    123

    MImageGetter、MTagHandler 如下:

    ndroid富文本编辑器支持html的导入与导出源码

    源码下载:http://www.dandroid.cn/?p=3278

    android基于exoPlayer 自定义播放器源码

    源码下载:http://www.dandroid.cn/?p=3275