TextView设置html标签内容

需求背景:
内容通知来自服务端的推送,因为不一样的活动需要,推送不一样的内容,内容的组成部分为html,都是前端的标签,可能有多个不同网址。
而app内,要使用TextView来显示html的内容,因为内容的不一样,以及内置的链接要适用跳转到app内的各个模块;
这里写图片描述

内容分析:
从需求来看,主要有以下几点注意:
1、活动内容不一致,html包含各种不同的格式;
2、内容都是html标签;
3、通知类型多,内含的网址可以跳到各个模块,这里就要求在识别网址时,要做分流;
4、一个通知可能含有几个不一样的网址;

技术分析:
1、在Android中Html.fromHtml()方法可以把Html标签内容转化为TextView所要显示的内容;
2、如何实现点击不同的链接可以跳转呢?一个TextView要实现内容可以点击,我们可以想到SpannableStringBuilder,设置setMovementMethod和setspan可以实现跳转了;
3、现在还有个攻克的难点,我怎么知道里面有多少条网址链接,我怎么知道点击哪个textview的哪个地方可以触发对应的链接呢?
查资料发现,html内容设置进去后,会set对应的setspan,这时候,我们可以使用
“URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);”
来获取总共有多少个网址链接,在根据spanned匹配的开始和结束,我们能够知道怎么去响应对应的链接了;

具体代码如下:

**
 * Created by azhansy 2017/2/13.
 * 显示 HTML 的textView
 */
public class HtmlTextView extends TextView {

    public HtmlTextView(Context context) {
        this(context, null);
    }

    public HtmlTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HtmlTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setMovementMethod(LocalLinkMovementMethod.getInstance());
    }

    public HtmlSpannableStringBuilder setHtmlText(String htmlText) {
        return new HtmlSpannableStringBuilder(htmlText);
    }

    public static class LocalLinkMovementMethod extends LinkMovementMethod {
        private static final long CLICK_DELAY = 500L;
        private long lastClickTime;
        static LocalLinkMovementMethod sInstance;

        public static LocalLinkMovementMethod getInstance() {
            if (sInstance == null)
                sInstance = new LocalLinkMovementMethod();

            return sInstance;
        }

        @Override
        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);

                if (link.length != 0) {
                    if (action == MotionEvent.ACTION_UP) {
                        //长按 和 点击过快 不执行点击事件
                        if (System.currentTimeMillis() - lastClickTime < CLICK_DELAY &&
                                !Utils.isFastDoubleClick(1000L)) {
                            link[0].onClick(widget);
                        }
                    } else {
                        Selection.setSelection(buffer,
                                buffer.getSpanStart(link[0]),
                                buffer.getSpanEnd(link[0]));
                        lastClickTime = System.currentTimeMillis();
                    }

                    return true;
                } else {
                    Selection.removeSelection(buffer);
                    Touch.onTouchEvent(widget, buffer, event);
                    return false;
                }
            }
            return Touch.onTouchEvent(widget, buffer, event);
        }
    }

    public class HtmlSpannableStringBuilder extends SpannableStringBuilder {
        /**
         * @param htmlLinkText
         */
        public HtmlSpannableStringBuilder(String htmlLinkText) {
            updateClickSpan(htmlLinkText);
        }

        /**
         * 更新Span
         *
         * @param htmlLinkText
         */
        private void updateClickSpan(String htmlLinkText) {
            setText(Html.fromHtml(htmlLinkText));
            CharSequence text = getText();
            if (text instanceof Spannable) {
                int end = text.length();
                Spannable sp = (Spannable) getText();
                URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
                SpannableStringBuilder style = new SpannableStringBuilder(text);
                style.clearSpans(); // should clear old spans
                for (URLSpan url : urls) {
                    // 设置Span
                    int startSpan = sp.getSpanStart(url);
                    int endSpan = sp.getSpanEnd(url);
                    if (startSpan >= 0) {
                        style.setSpan(new Clickable(new URLClickListener(url.getURL())), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }

                    Logger.d("azhansy: 链接", url.getURL());
                }
                setText(style);
            }
        }

        //TextView中的Span区域点击事件
        class Clickable extends ClickableSpan implements View.OnClickListener {


            private final View.OnClickListener mListener;


            public Clickable(View.OnClickListener l) {
                mListener = l;
            }


            @Override
            public void onClick(View widget) {

                mListener.onClick(widget);
            }


            @Override
            public void updateDrawState(TextPaint ds) {
                super.updateDrawState(ds);
                ds.setUnderlineText(false);
                ds.setColor(Color.parseColor("#556B95"));
            }
        }


        private class URLClickListener implements View.OnClickListener {


            private String url;

            URLClickListener(String url) {
                this.url = url;
            }

            @Override
            public void onClick(View arg0) {
                Logger.d("azhansy: 点击后的链接 ", url);
               //这里可以分流点击的链接
                    }
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/azhansy/article/details/58622102