在 WebView 而不是默认浏览器中打开 URL [英] Open URL in WebView instead of default Browser

查看:18
本文介绍了在 WebView 而不是默认浏览器中打开 URL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建简单的 Webview 应用程序,其中包含 textview 上的一些链接,并在 webview 而不是默认浏览器中打开这些链接.我的 textview 包含各种不同的 URL,我正在尝试在我的应用程序的 webview 中打开每个链接.

I am creating simple Webview application with some links on textview and open those links in webview instead of default browser. My textview contains various different URLS and i am trying to open each link in webview of my app.

这里代码:

tv.setText("www.google.com  www.facebook.com  www.yahoo.com");
tv.setMovementMethod(LinkMovementMethod.getInstance());;
tv.setText(Html.fromHtml(tv.getText().toString()));
Linkify.addLinks(tv, Linkify.WEB_URLS);


WebViewClient yourWebClient = new WebViewClient()
       {
           // Override page so it's load on my view only
           @Override
           public boolean shouldOverrideUrlLoading(WebView  view, String  url)
           {
            // This line we let me load only pages inside Firstdroid Webpage
            if ( url.contains("www") == true )
               // Load new URL Don't override URL Link
               return false;

            // Return true to override url loading (In this case do nothing).
            return true;
           }
       };

wv.getSettings().setJavaScriptEnabled(true);   
    wv.getSettings().setSupportZoom(true);      

    wv.getSettings().setBuiltInZoomControls(true); 
    wv.setWebViewClient(yourWebClient);

    // Load URL
    wv.loadUrl(url);

已经尝试过 this, 这个this 示例但无法解决 textview 中的多个链接的问题.请帮我解决这个问题.感谢您的帮助.

Already tried with this, this and this examples but couldn't solve my issue with multiple links in the textview. Please help me to solve this problem. Thanks for your help.

编辑我的 Textview 包含如下字符串:

Edit My Textview contains strings like:

hello xyz some more statements... xyz.com/abc/
hello xyz some more statements... xyz.com/abc/
hello xyz some more statements... xyz.com/abc/
hello xyz some more statements... xyz.com/abc/

像这样它有很多字符串和多个 URL

Like this it has many strings and multiple URL's

推荐答案

需要解决以下问题:

  1. 链接 TextView
  2. 找到一种方法来监听对 TextView 中链接的点击
  3. 获取点击链接的url并加载到WebView中
  4. 可选:使 TextView 可点击而不失去选择文本的能力
  5. 可选:处理 TextView 中的格式化文本(不同的文本大小和样式)

#1 链接 TextView

这是最简单的问题,你已经解决了.我建议这样做:

That's the easiest problem and you already solved that one. I suggest to do it this way:

String text = "These are some sample links:
www.google.com
www.facebook.com
www.yahoo.com";
Spannable spannable = new SpannableString( Html.fromHtml(text) );
Linkify.addLinks(spannable, Linkify.WEB_URLS);

我在这里使用 Spannable 来解决问题 #2.

I'm using a Spannable here to solve problem #2.

#2 + #3 监听链接点击并在 WebView 中打开它们

要找出链接何时被点击并检索我们必须打开的 URL,我们将 TextView 中的所有 URLSpan 替换为我们的 LinkSpan(这就是我们需要 Spannable 的原因):

To find out when a link is clicked and retrieve the URL we have to open, we replace all URLSpans in the TextView by our LinkSpan (that's why we need a Spannable):

URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
for (URLSpan urlSpan : spans) {
    LinkSpan linkSpan = new LinkSpan(urlSpan.getURL());
    int spanStart = spannable.getSpanStart(urlSpan);
    int spanEnd = spannable.getSpanEnd(urlSpan);
    spannable.setSpan(linkSpan, spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    spannable.removeSpan(urlSpan);
}

我们的 LinkSpan 只是抓取点击的 url 并在 WebView 中打开它:

Our LinkSpan simply grabs the clicked url and opens it in the WebView:

private class LinkSpan extends URLSpan {
    private LinkSpan(String url) {
        super(url);
    }

    @Override
    public void onClick(View view) {
        String url = getURL();
        if (mWebView != null && url != null) {
            mWebView.loadUrl(url);
        }
    }
}

现在显然我们必须在实例变量中保留对 WebView 的引用才能使其工作.为了使这个答案尽可能简短,我选择将 LinkSpan 定义为内部类,但我建议将其定义为顶级.注册一个监听器或将 WebView 作为参数传递给构造函数.

Now obviously we have to keep a reference to the WebView in an instance variable to make this work. To make this answer as short as possible I chose to define LinkSpan as an inner class but I'd recommend to define it as a top-level. Register a listener or pass the WebView as a parameter to the constructor instead.

如果没有将 MovementMethod 设置为 LinkMovementMethod,TextView 根本不会打开链接:

Without setting the MovementMethod to LinkMovementMethod the TextView won't open links at all:

tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setText(spannable, BufferType.SPANNABLE);

最后但同样重要的是,让我们确保 WebView 不会启动浏览器,而是在应用程序中加载页面:

Last but not least let's make sure the WebView doesn't start the browser but loads the page within the app:

mWebView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // we handle the url ourselves if it's a network url (http / https) 
        return ! URLUtil.isNetworkUrl(url);
    }
});

#4 可点击和可选择的TextView + #5 格式化文本

如果 MovementMethod 设置为 LinkMovementMethod,您可以单击链接,但不能再选择文本(您需要 ArrowKeyMovementMethod).为了解决这个问题,我创建了一个继承自 ArrowKeyMovementMethod 的自定义 MovementMethod 类,并添加了单击链接的功能.最重要的是,它能够处理格式化的文本.因此,如果您决定在 TextView 中使用不同的字体大小和样式,下面的 MovementMethod 将涵盖它(也适用于 EditTexts):

If the MovementMethod is set to LinkMovementMethod you can click links but you can't select text any more (you need ArrowKeyMovementMethod for that). To solve this I created an custom MovementMethod class that inherits from ArrowKeyMovementMethod and adds the ability to click links. On top of that it is able to deal with formatted text. So if you decide to use different font sizes and styles in the TextView the following MovementMethod will have it covered (works with EditTexts as well):

/**
 * ArrowKeyMovementMethod does support selection of text but not the clicking of links.
 * LinkMovementMethod does support clicking of links but not the selection of text.
 * This class adds the link clicking to the ArrowKeyMovementMethod.
 * We basically take the LinkMovementMethod onTouchEvent code and remove the line
 *      Selection.removeSelection(buffer);
 * which deselects all text when no link was found.
 */
public class EnhancedLinkMovementMethod extends ArrowKeyMovementMethod {

    private static EnhancedLinkMovementMethod sInstance;

    private static Rect sLineBounds = new Rect();

    public static MovementMethod getInstance() {
        if (sInstance == null) {
            sInstance = new EnhancedLinkMovementMethod();
        }
        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 index = getCharIndexAt(widget, event);
            if (index != -1) {
                ClickableSpan[] link = buffer.getSpans(index, index, 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);
    }

    private int getCharIndexAt(TextView textView, MotionEvent event) {
        // get coordinates
        int x = (int) event.getX();
        int y = (int) event.getY();
        x -= textView.getTotalPaddingLeft();
        y -= textView.getTotalPaddingTop();
        x += textView.getScrollX();
        y += textView.getScrollY();

        /*
         * Fail-fast check of the line bound.
         * If we're not within the line bound no character was touched
         */
        Layout layout = textView.getLayout();
        int line = layout.getLineForVertical(y);
        synchronized (sLineBounds) {
            layout.getLineBounds(line, sLineBounds);
            if (! sLineBounds.contains(x, y)) {
                return -1;
            }
        }

        // retrieve line text
        Spanned text = (Spanned) textView.getText();
        int lineStart = layout.getLineStart(line);
        int lineEnd = layout.getLineEnd(line);
        int lineLength = lineEnd - lineStart;
        if (lineLength == 0) {
            return -1;
        }
        Spanned lineText = (Spanned) text.subSequence(lineStart, lineEnd);

        // compute leading margin and subtract it from the x coordinate
        int margin = 0;
        LeadingMarginSpan[] marginSpans = lineText.getSpans(0, lineLength, LeadingMarginSpan.class);
        if (marginSpans != null) {
            for (LeadingMarginSpan span : marginSpans) {
                margin += span.getLeadingMargin(true);
            }
        }
        x -= margin;

        // retrieve text widths
        float[] widths = new float[lineLength];
        TextPaint paint = textView.getPaint();
        paint.getTextWidths(lineText, 0, lineLength, widths);

        // scale text widths by relative font size (absolute size / default size)
        final float defaultSize = textView.getTextSize();
        float scaleFactor = 1f;
        AbsoluteSizeSpan[] absSpans = lineText.getSpans(0, lineLength, AbsoluteSizeSpan.class);
        if (absSpans != null) {
            for (AbsoluteSizeSpan span : absSpans) {
                int spanStart = lineText.getSpanStart(span);
                int spanEnd = lineText.getSpanEnd(span);
                scaleFactor = span.getSize() / defaultSize;
                int start = Math.max(lineStart, spanStart);
                int end = Math.min(lineEnd, spanEnd);
                for (int i = start; i < end; i++) {
                    widths[i] *= scaleFactor;
                }
            }
        }

        // find index of touched character
        float startChar = 0;
        float endChar = 0;
        for (int i = 0; i < lineLength; i++) {
            startChar = endChar;
            endChar += widths[i];
            if (endChar >= x) {
                // which "end" is closer to x, the start or the end of the character?
                int index = lineStart + (x - startChar < endChar - x ? i : i + 1);
                //Logger.e(Logger.LOG_TAG, "Found character: " + (text.length()>index ? text.charAt(index) : ""));
                return index;
            }
        }

        return -1;
    }
}

完整的活动代码

这是我使用的完整示例活动代码.它应该完全符合您的要求.它使用的是我的 EnhandedMovementMethod,但您可以使用简单的 LinkMovementMethod(具有前面提到的缺点).

Here's the complete sample Activity code that I used. It should do exactly what you want. It's using my EnhandedMovementMethod but you can use a simple LinkMovementMethod (with the drawbacks mentioned before).

public class LinkTestActivity extends Activity {

    private WebView mWebView;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webView);
        TextView tv = (TextView) findViewById(R.id.textView);

        String text = "These are some sample links:
www.google.com
www.facebook.com
www.yahoo.com";

        // Linkify the TextView
        Spannable spannable = new SpannableString( Html.fromHtml(text) );
        Linkify.addLinks(spannable, Linkify.WEB_URLS);

        // Replace each URLSpan by a LinkSpan
        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
        for (URLSpan urlSpan : spans) {
            LinkSpan linkSpan = new LinkSpan(urlSpan.getURL());
            int spanStart = spannable.getSpanStart(urlSpan);
            int spanEnd = spannable.getSpanEnd(urlSpan);
            spannable.setSpan(linkSpan, spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            spannable.removeSpan(urlSpan);
        }

        // Make sure the TextView supports clicking on Links
        tv.setMovementMethod(EnhancedLinkMovementMethod.getInstance());
        tv.setText(spannable, BufferType.SPANNABLE);

        // Make sure we handle clicked links ourselves
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // we handle the url ourselves if it's a network url (http / https) 
                return ! URLUtil.isNetworkUrl(url);
            }
        });

        mWebView.getSettings().setJavaScriptEnabled(true);   
        mWebView.getSettings().setSupportZoom(true);      
        mWebView.getSettings().setBuiltInZoomControls(true);
    }

    private class LinkSpan extends URLSpan {
        private LinkSpan(String url) {
            super(url);
        }

        @Override
        public void onClick(View view) {
            String url = getURL();
            if (mWebView != null && url != null) {
                mWebView.loadUrl(url);
            }
        }
    }
}

这篇关于在 WebView 而不是默认浏览器中打开 URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆