美文网首页安卓开发Android知识点和文章分享
Android用内置WebView打开TextView文本中的超

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

作者: 木月下的PP | 来源:发表于2018-10-24 19:23 被阅读181次

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

    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文本中的超

        本文链接:https://www.haomeiwen.com/subject/uuvxtqtx.html