Android用内置WebView打开TextView文本中的超链接

    下午产品经理提了个需求:要在服务端传来的文本中用应用内置浏览器打开超链接。
去网上搜了下,找到了个方法:

textView.setMovementMethod(LinkMovementMethod.getInstance());

很遗憾,发现这只是跳转到浏览器的方法。
    又看了下网友们的方法,基本都要涉及到SpannableString的设置;或是自定义UrlSpan,重写它的onClick方法;有些还要遍历文本寻找以http开头的字符串。总之就是很麻烦。
    这些方法很多最后都要用到textView.setText()的方法,但是因为我要解析图片,这个方法已经用掉了,无法重复使用:

textView.setText(Html.fromHtml(str,  new MImageGetter(textView, getApplicationContext()), null));

    所以这些方法都行不通。那行,换种思路,我看看LinkMovementMethod的源码是怎么实现跳转的。源码有点长,这里只贴出关键代码,就是下面的onTouchEvent。

@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) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                                           buffer.getSpanStart(link[0]),
                                           buffer.getSpanEnd(link[0]));
                }
                return true;
            } else {
                Selection.removeSelection(buffer);
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }

    可以看到,执行跳转的语句是在:

if (action == MotionEvent.ACTION_UP) {
        link[0].onClick(widget);
 }

    这样就简单了,我就自定义了一个类WebLinkMethod来继承LinkMovementMethod 并重写onTouchEvent()这个方法:

public class WebLinkMethod extends LinkMovementMethod {

    private static WebLinkMethod instance;
    private Context context;

    private WebLinkMethod(Context context) {
        this.context = context;
    }

    public static MovementMethod getInstance(Context context) {
        if (instance == null)
            instance = new WebLinkMethod(context);
        return instance;
    }

    @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);
            URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
//                  link[0].onClick(widget);
                    Intent intent = new Intent(context, H5Activity.class);
                    intent.putExtra("url", link[0].getURL());
                    context.startActivity(intent);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                }
                return true;
            } else {
                Selection.removeSelection(buffer);
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }
}

    说下几个改动(代码中注释的两行):

  1. 由于页面跳转我们需要用到原页面的上下文,于是修改了构造函数,加入了Context;
  2. URLSpan是ClickableSpan的子类,实现了getURL()的方法,所以这里要换成它我们才能取到链接地址,link[0]就是我们点击到的超链接字符串,通过link[0].getURL()我们可以获得它的链接地址传给下个页面;
  3. 有了上下文context和链接地址url,我们就可以把原来的跳转语句换成我们自己的,跳转到包含webView的界面就大功告成了。

    最后的方案虽然很简单,但是网上的解答都不尽如人意。所以献丑记下解决的过程,希望能帮助到有需要的人~

你可能感兴趣的:(Android用内置WebView打开TextView文本中的超链接)