HtmlSpanner 是一个能够把Html源代码解析成spannablestring的开源库.

基本的使用方法很简单,使用
new HtmlSpanner().fromHtml(content);// content是html源代码
注意,fromHtml方法不能够在主线程中调用.

其他一些功能
1.能够获取标签属性和自定义标签属性,使用工具,HtmlCleaner,这个工具网上资料比较多。
2.handlers,HtmlSpanner提供了很多Handlers用于对不同标签进行处理。
3.spans,HtmlSpanner提供了多个span能够使用。
4.css

我 以动态添加可以点击的imagespan为例,介绍handlers的用法。
在activity中创建自己的HtmlSpanner

存在这么一个需求:加载html文档到本地,通过HtmlSpanner解析成spannablestring,显示,并且能够使里面的image可点击,并执行点击事件。
我们需要 htmlspanner
private HtmlSpanner htmlSpanner = new HtmlSpanner();
TagNodeHandler
其实这里的TagNodeHandler使用的是HtmlSpanner中的 ImageHandler (ImageHandler是处理img标签的handler)只是改了部分代码,更适合我使用而已 你也可以参考ImageHandler的源码创建自己的ImageHandler

private TagNodeHandler tagNodeHandler = new TagNodeHandler() {
        @Override
        public void handleTagNode(TagNode node, final SpannableStringBuilder builder, final int start, final int end, final SpanStack spanStack) {
            final String src = node.getAttributeByName("src");
            imageUrls[imageCount] = src;
            imageCount ++;
            builder.append("\uFFFC");
            Bitmap loadBitmap = loadBitmap(src);
            int toHeight = loadBitmap.getHeight() * textViewWidth / loadBitmap.getWidth();
            Bitmap bitmap = Bitmap.createScaledBitmap(loadBitmap, textViewWidth, toHeight, true);
            if (bitmap != null) {
                Drawable drawable = new BitmapDrawable(bitmap);
                drawable.setBounds(0, 0, bitmap.getWidth() - 1,
                        bitmap.getHeight() - 1);
                spanStack.pushSpan(new ClickableImageSpan(drawable) {
                    @Override
                    public void onClick(View view) {
                        // do your job
                }, start, builder.length());

然后需要注册该handler
htmlSpanner.registerHandler("img", tagNodeHandler);
之后调起线程处理html
new GetHtmlSpannerThread(mHandler, htmlSpanner, content).start();
最后得到结果

case KEY_GET_HTML_SPANNER_SUC:
                    Spannable spannable = (Spannable) msg.obj;
                    if (null != spannable){
                        tv_detail_intro.setText(spannable);
                    } else{
                        tv_detail_intro.setText("加载失败");
                    break;

自定义的ClickableImageSpan

public abstract class ClickableImageSpan extends ImageSpan {
    public ClickableImageSpan(Drawable b) {
        super(b);
    public abstract void onClick(View view);

自定义的ClickableMovementMethod 。是这样的,网上某大神添加可点击的imagespan,发现imagespan是不能点击的,然后他翻了LinkMovementMethod的源码,发现里面只检测了ClickableSpan的点击事件,所以他改了一些东西,写了个ClickableMovementMethod,的东西,只需要调用tv_detail_intro.setMovementMethod(new ClickableMovementMethod());,就可以使上面定义的ClickableImageSpan可被点击了。
ClickableMovementMethod 源码

public class ClickableMovementMethod extends LinkMovementMethod {
    private static ClickableMovementMethod sInstance;
    public static ClickableMovementMethod getInstance() {
        if (sInstance == null) {
            sInstance = new ClickableMovementMethod();
        return sInstance;
    public boolean onTouchEvent(TextView widget, Spannable buffer,
                                MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            x -= widget.getTotalPaddingLeft();
            y -= widget.getTotalPaddingTop();
            x += widget.getScrollX();
            y += widget.getScrollY();
            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);
            ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
            ClickableImageSpan[] imageSpans = buffer.getSpans(off, off, ClickableImageSpan.class);
            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                return true;
            } else if (imageSpans.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    imageSpans[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(imageSpans[0]),
                            buffer.getSpanEnd(imageSpans[0]));
                return true;
            } else {
                Selection.removeSelection(buffer);
        return false;
                    HtmlSpanner是一个能够把Html源代码解析成spannablestring的开源库.基本的使用方法很简单,使用     new    HtmlSpanner().fromHtml(content);// content是html源代码 注意,fromHtml方法不能够在主线程中调用.其他一些功能 1.能够获取标签属性和自定义标签属性,使用工具,HtmlCleaner,这个工具网上资
Gradle依赖关系:
 implementation 'com.github.NightWhistler:HtmlSpanner:0.4'
 HtmlSpanner最初是PageTurnerHTML呈现库,但通过查看StackOverflow上的一些问题,我注意到有多少人正在为臭名昭著的Html.fromHtml()苦苦挣扎,并使其结果正确显示在TextViews中。
 HtmlSpanner允许您完全控制标记的呈现方式,并为您提供有关标记在文本中位置的所有数据。 这样可以正确处理锚点,表,编号列表和无序列表。
 默认的链接实现只是打开URL,但是可以轻松地覆盖它以支持锚点。
 HtmlSpanner使用HtmlCleaner来完成大部分繁重的工作,以解析HTML文件。
CSS支持
HtmlSpanner现在还支持CSS的最常见子集:默认情况下会解析样式标
2.可以使用HtmlSpanner
Html不需要依赖任何库但是由于自身自带的HTML支持的标签很少,不能满足我们的需求,那我们就会寻找其他解决方案,例如HtmlSpannerHtmlSpanner是支持大多数标签的解析库,但是...
Android-Universal-Image-Loader:com.nostra13.universalimageloader:异步加载、缓存、显示图片
ImageLoader:com.novoda.imageloader:异步加载、缓存、显示图片
picasso:com.squareup.picasso:功能强大的图片下载缓存库
PhotoView:uk\co\sen
                Error fetching https://ruby.taobao.org/: bad response Not Found 404 (http://r
                    万象Vientiane: 
                    大哥,https,不是http
                Python3.5 Django1.8 apache2.4 Ubuntu 配置mod_wsgi模块
                    小梁L同学: 
                    你好!我遇到和你一样的问题,就是在升级python3 ,并且将软链改为python3之后 出现mod_wsgi无法编译的情况 但是我的方法是  ./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python2  不知道是为什么