在WebView中打开URL而不是默认浏览器。

时间:2022-09-04 12:37:07

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.

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

Here code:

下面的代码:

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

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:

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

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/

Like this it has many strings and multiple URL's

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

6 个解决方案

#1


22  

The following problems need to be solved:

以下问题需要解决:

  1. Linkify the TextView
  2. 其内的TextView
  3. Find a way to listen to a click on a link in the TextView
  4. 找到一种方法来监听TextView中的链接。
  5. Get the url of the clicked link and load it in the WebView
  6. 获取单击链接的url并将其加载到WebView中。
  7. Optional: make the TextView clickable without losing the ability to select text
  8. 可选:使TextView可点击而不失去选择文本的能力。
  9. Optional: handle formatted text in the TextView (different text sizes and styles)
  10. 可选:在TextView中处理格式化的文本(不同的文本大小和样式)

#1 Linkify the 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:\nwww.google.com\nwww.facebook.com\nwww.yahoo.com";
Spannable spannable = new SpannableString( Html.fromHtml(text) );
Linkify.addLinks(spannable, Linkify.WEB_URLS);

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

我用一个Spannable来解决问题#2。

#2 + #3 Listen to clicks on links and open them in the WebView

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

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):

要知道何时单击链接并检索我们必须打开的URL,我们将用LinkSpan替换TextView中的所有urlspan(这就是为什么我们需要一个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);
}

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

我们的LinkSpan只抓取点击的url并在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);
        }
    }
}

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.

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

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

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

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

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

最后,让我们确保WebView不会启动浏览器,而是载入应用程序中的页面:

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 Clickable and selectable TextView + #5 formatted Text

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

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):

如果移动方法设置为LinkMovementMethod,你可以点击链接,但是你不能再选择文本了(你需要使用ArrowKeyMovementMethod)。为了解决这个问题,我创建了一个自定义的MovementMethod类,它继承了ArrowKeyMovementMethod,并添加了单击链接的功能。除此之外,它还能处理格式化的文本。因此,如果你决定在TextView中使用不同的字体大小和样式,下面的MovementMethod将会覆盖(与EditTexts一起工作):

/**
 * 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;
    }
}

Complete Activity code

完整的活动代码

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).

下面是我使用的完整示例活动代码。它应该做你想做的。它使用我的增强移动方法,但您可以使用简单的LinkMovementMethod(前面提到的缺点)。

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:\nwww.google.com\nwww.facebook.com\nwww.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);
            }
        }
    }
}

#2


2  

The WebViewClient is set by call setWebViewClient() method on you WebView refrence.

WebView客户端是通过WebView的方法,通过调用setWebViewClient()方法设置的。

Firstly set all properties for webview then call loadURL(String url) method, It will open sublinks to same webview instead of open into browser.

首先设置webview的所有属性,然后调用loadURL(String url)方法,它将打开sublinks到相同的webview,而不是打开到浏览器。

ProgressDialog progressDialog = new ProgressDialog(WebActivity.this);
WebView webview= (WebView) findViewById(R.id.webview);

webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.setVerticalScrollBarEnabled(false);
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.getSettings().setPluginsEnabled(true);
webview.getSettings().setSupportMultipleWindows(true);
webview.getSettings().setSupportZoom(true);
webview.setVerticalScrollBarEnabled(false);
webview.setHorizontalScrollBarEnabled(false);

webview.loadUrl("http://www.google.com");

webview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        progressDialog.dismiss();
    }

    @Override
    public void onPageStarted(WebView view, String url,Bitmap favicon) {
        // TODO Auto-generated method stub
        super.onPageStarted(view, url, favicon);
        progressDialog.setMessage("Loading ...");
        progressDialog.setCancelable(false);
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
    }
});

#3


1  

Your Webview Application will receive Link when some link is clicked. User manually have to select your application. specifying host "like www.apptechinc.com" will launch this application when any link from that site is clicked.

当点击某个链接时,您的Webview应用程序将接收链接。用户必须手动选择您的应用程序。当单击该站点的任何链接时,指定主机“如www.apptechinc.com”将启动该应用程序。

    <activity
    android:name=".MainActivity"
    android:label="@string/title_activity_main" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:host="www.apptecxinc.com" />
    </intent-filter>
    </activity>

In Activity you can receive this link as :

在活动中,您可以收到以下链接:

    String action = getIntent().getAction();
    if (Intent.ACTION_VIEW.equals(action)) {
        Uri uri = getIntent().getData();
            webview.loadUrl(urlsetup(uri.getPath())); 

    } 

#4


0  

The issue appears to be that Linkify is looking for a scheme to detect links. Without http://, it isn't detecting your links as web URLs. The solution would be to make sure your links include the scheme or define a custom regular expression pattern to match. It's not clear from your sample TextView data what the pattern should be. Here's a page that shows how to use the custom pattern once you work out what it is.

问题似乎是Linkify正在寻找一个检测链接的方案。没有http://,它没有检测你的链接作为web url。解决方案是确保您的链接包含该方案或定义一个定制的正则表达式模式来匹配。从您的示例TextView数据中不清楚该模式应该是什么。这里有一个页面,展示了如何使用自定义模式。

#5


0  

The most important part of @Emanuel Moecklin 's answer is to subclass URLSpan and create your own URLSpan which has onClick overrided.

@Emanuel Moecklin的答案最重要的部分是将URLSpan子类化,并创建自己的URLSpan。

Inspired by his answer, instead of following fully his steps, I sticked to using Linkify. However, for some other reasons, I created my own Linkify class, with almost the same code as original Linkify.

受他的回答启发,我没有完全按照他的步骤去做,而是坚持使用Linkify。但是,出于其他原因,我创建了自己的Linkify类,几乎与原始的Linkify代码相同。

And then, inside applyLink() in Linkify, I replaced

然后,在Linkify的applyLink()中,我替换了。

URLSpan span = new URLSpan(url);

with

InAppURLSpan span = new InAppURLSpan(url);

Where the code for InAppURLSpan is:

InAppURLSpan的代码是:

public static class InAppURLSpan extends URLSpan {

    public InAppURLSpan(String url) {
        super(url);
    }

    @Override
    public void onClick(View widget) {
        String url = getURL();
        Log.i("TNC_URL", url);
        Intent intent = new Intent(widget.getContext(), SingleWebViewActivity.class);
        intent.putExtra(Constants.INTENT_URL, url);
        widget.getContext().startActivity(intent);
    }
}

And it worked like a charm~

它就像一种魅力。

#6


-1  

WebView wv = (WebView) findViewById(R.id.webView1);
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setSupportZoom(true);      

wv.getSettings().setBuiltInZoomControls(true);

wv.setWebViewClient(new WebViewClient()
{
    // Links clicked will be shown on the webview
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url)
    {
        return super.shouldOverrideUrlLoading(view, url);
    }   
}); 
wv.loadUrl(url);

#1


22  

The following problems need to be solved:

以下问题需要解决:

  1. Linkify the TextView
  2. 其内的TextView
  3. Find a way to listen to a click on a link in the TextView
  4. 找到一种方法来监听TextView中的链接。
  5. Get the url of the clicked link and load it in the WebView
  6. 获取单击链接的url并将其加载到WebView中。
  7. Optional: make the TextView clickable without losing the ability to select text
  8. 可选:使TextView可点击而不失去选择文本的能力。
  9. Optional: handle formatted text in the TextView (different text sizes and styles)
  10. 可选:在TextView中处理格式化的文本(不同的文本大小和样式)

#1 Linkify the 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:\nwww.google.com\nwww.facebook.com\nwww.yahoo.com";
Spannable spannable = new SpannableString( Html.fromHtml(text) );
Linkify.addLinks(spannable, Linkify.WEB_URLS);

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

我用一个Spannable来解决问题#2。

#2 + #3 Listen to clicks on links and open them in the WebView

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

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):

要知道何时单击链接并检索我们必须打开的URL,我们将用LinkSpan替换TextView中的所有urlspan(这就是为什么我们需要一个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);
}

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

我们的LinkSpan只抓取点击的url并在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);
        }
    }
}

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.

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

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

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

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

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

最后,让我们确保WebView不会启动浏览器,而是载入应用程序中的页面:

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 Clickable and selectable TextView + #5 formatted Text

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

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):

如果移动方法设置为LinkMovementMethod,你可以点击链接,但是你不能再选择文本了(你需要使用ArrowKeyMovementMethod)。为了解决这个问题,我创建了一个自定义的MovementMethod类,它继承了ArrowKeyMovementMethod,并添加了单击链接的功能。除此之外,它还能处理格式化的文本。因此,如果你决定在TextView中使用不同的字体大小和样式,下面的MovementMethod将会覆盖(与EditTexts一起工作):

/**
 * 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;
    }
}

Complete Activity code

完整的活动代码

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).

下面是我使用的完整示例活动代码。它应该做你想做的。它使用我的增强移动方法,但您可以使用简单的LinkMovementMethod(前面提到的缺点)。

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:\nwww.google.com\nwww.facebook.com\nwww.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);
            }
        }
    }
}

#2


2  

The WebViewClient is set by call setWebViewClient() method on you WebView refrence.

WebView客户端是通过WebView的方法,通过调用setWebViewClient()方法设置的。

Firstly set all properties for webview then call loadURL(String url) method, It will open sublinks to same webview instead of open into browser.

首先设置webview的所有属性,然后调用loadURL(String url)方法,它将打开sublinks到相同的webview,而不是打开到浏览器。

ProgressDialog progressDialog = new ProgressDialog(WebActivity.this);
WebView webview= (WebView) findViewById(R.id.webview);

webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setJavaScriptEnabled(true);
webview.setVerticalScrollBarEnabled(false);
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.getSettings().setPluginsEnabled(true);
webview.getSettings().setSupportMultipleWindows(true);
webview.getSettings().setSupportZoom(true);
webview.setVerticalScrollBarEnabled(false);
webview.setHorizontalScrollBarEnabled(false);

webview.loadUrl("http://www.google.com");

webview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        progressDialog.dismiss();
    }

    @Override
    public void onPageStarted(WebView view, String url,Bitmap favicon) {
        // TODO Auto-generated method stub
        super.onPageStarted(view, url, favicon);
        progressDialog.setMessage("Loading ...");
        progressDialog.setCancelable(false);
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
    }
});

#3


1  

Your Webview Application will receive Link when some link is clicked. User manually have to select your application. specifying host "like www.apptechinc.com" will launch this application when any link from that site is clicked.

当点击某个链接时,您的Webview应用程序将接收链接。用户必须手动选择您的应用程序。当单击该站点的任何链接时,指定主机“如www.apptechinc.com”将启动该应用程序。

    <activity
    android:name=".MainActivity"
    android:label="@string/title_activity_main" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:host="www.apptecxinc.com" />
    </intent-filter>
    </activity>

In Activity you can receive this link as :

在活动中,您可以收到以下链接:

    String action = getIntent().getAction();
    if (Intent.ACTION_VIEW.equals(action)) {
        Uri uri = getIntent().getData();
            webview.loadUrl(urlsetup(uri.getPath())); 

    } 

#4


0  

The issue appears to be that Linkify is looking for a scheme to detect links. Without http://, it isn't detecting your links as web URLs. The solution would be to make sure your links include the scheme or define a custom regular expression pattern to match. It's not clear from your sample TextView data what the pattern should be. Here's a page that shows how to use the custom pattern once you work out what it is.

问题似乎是Linkify正在寻找一个检测链接的方案。没有http://,它没有检测你的链接作为web url。解决方案是确保您的链接包含该方案或定义一个定制的正则表达式模式来匹配。从您的示例TextView数据中不清楚该模式应该是什么。这里有一个页面,展示了如何使用自定义模式。

#5


0  

The most important part of @Emanuel Moecklin 's answer is to subclass URLSpan and create your own URLSpan which has onClick overrided.

@Emanuel Moecklin的答案最重要的部分是将URLSpan子类化,并创建自己的URLSpan。

Inspired by his answer, instead of following fully his steps, I sticked to using Linkify. However, for some other reasons, I created my own Linkify class, with almost the same code as original Linkify.

受他的回答启发,我没有完全按照他的步骤去做,而是坚持使用Linkify。但是,出于其他原因,我创建了自己的Linkify类,几乎与原始的Linkify代码相同。

And then, inside applyLink() in Linkify, I replaced

然后,在Linkify的applyLink()中,我替换了。

URLSpan span = new URLSpan(url);

with

InAppURLSpan span = new InAppURLSpan(url);

Where the code for InAppURLSpan is:

InAppURLSpan的代码是:

public static class InAppURLSpan extends URLSpan {

    public InAppURLSpan(String url) {
        super(url);
    }

    @Override
    public void onClick(View widget) {
        String url = getURL();
        Log.i("TNC_URL", url);
        Intent intent = new Intent(widget.getContext(), SingleWebViewActivity.class);
        intent.putExtra(Constants.INTENT_URL, url);
        widget.getContext().startActivity(intent);
    }
}

And it worked like a charm~

它就像一种魅力。

#6


-1  

WebView wv = (WebView) findViewById(R.id.webView1);
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setSupportZoom(true);      

wv.getSettings().setBuiltInZoomControls(true);

wv.setWebViewClient(new WebViewClient()
{
    // Links clicked will be shown on the webview
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url)
    {
        return super.shouldOverrideUrlLoading(view, url);
    }   
}); 
wv.loadUrl(url);