Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebView jump to anchor using loadDataWithBaseUrl

My Android app uses a WebView to display a bunch of HTML code that I generate 'on the fly'. The HTML code is loaded using the following code:

    StringBuilder builder = new StringBuilder();

    // HTML
    builder.append("<html><head><link rel=\"stylesheet\" href=\"file:///android_asset/style.css\" type=\"text/css\">");
    builder.append("</link></head><body>");
    builder.append(getThreadBody());
    builder.append("</body></html>");

    webview.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "utf-8", null);

This all works really nice. Note that I'm not loading an actual HTML file, I'm merely creating a string that represents some (hopefully valid) HTML and load it in the WebView.

Anyway, the HTML I generate (the part in the 'getThreadBody' method) contains named anchors, for example like this;

<div>
    <a name="949823">Anchor 1</a>
    <div>All kinds of stuff</div>

    <a name="895984">Anchor 2</a>
    <div>...</div>
</div>

Now in some cases I want the WebView to navigate to one of those anchors as soon as I load the HTML. As far as I understand the WebView supports navigating (scrolling in this case) to named anchors, but the catch is that nobody is clicking any hyperlinks to those anchors, I want the WebView to scroll when it is loaded (it is no problem if there is a short delay between loading the HTML and scrolling, my point is that it should not require user interaction).

I believe the behavior can be achieved by using the WebView's loadUrl method and supplying a URL with the anchor in place, eg

webview.loadUrl("file:///android_asset/page.html#895984", ...)

However, since I am not saving the HTML to any file I cannot use this method... Of course saving the HTML to a temporary file may be a solution but I'd like to keep that as a last resort, there must be a simpler way?

How can I achieve this? Thanks!


Resolved Here's the code that works. I found a short delay was required to let the page load before executing the javascript otherwise it was kind of 50/50 whether it worked or not...

    StringBuilder builder = new StringBuilder();

    // HTML
    builder.append("<html><head><link rel=\"stylesheet\" href=\"file:///android_asset/style.css\" type=\"text/css\">");
    builder.append("</link>");
    builder.append("<script>");
    builder.append("function scrollAnchor(id) {");
    builder.append("window.location.hash = id;}");
    builder.append("</script>");
    builder.append("</head><body>");
    builder.append(getThreadBody());
    builder.append("</body></html>");

    webContents.loadDataWithBaseURL("file:///android_asset/", builder.toString(), "text/html", "utf-8", null);

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            String id = "895884";
            webContents.loadUrl("javascript:scrollAnchor(" + id + ");");
        }
        }
    }, 250);
like image 954
Nick Thissen Avatar asked Dec 27 '12 23:12

Nick Thissen


2 Answers

How about control it by JavaScript? I didn't try it but maybe this is a clue.

builder.append(getThreadBody());
builder.append("<script>window.location.hash="949823";</script>");
builder.append("</body></html>");

Remember enable javascript for WebView.

----Additional Answer----

I saw that you use TimerTask to load the javascript, That works but I think there is another better way. WebView have a callback named onPageFinished and it will be trigger when WebView finish loading webpage. You could inject your JS there.

webContents.setWebViewClient(new WebViewClient(){

    @Override
    public void onPageFinished(WebView view, String url) {
          String id = "895884";
          webContents.loadUrl("javascript:scrollAnchor(" + id + ");");
    }

});

Hope this is useful!

like image 76
wayne_bai Avatar answered Oct 14 '22 20:10

wayne_bai


First of all, you don't need to use javascript. If you loaded content with

webContents.loadDataWithBaseURL("some://dummy/url",...);

you can simply scroll to anchor with

webContents.loadUrl("some://dummy/url#anchor");

Secondly, doing that on onPageFinished without additional control results in never ending loop! When loadUrl finishes onPageFinished get's called again and again.

like image 39
epint Avatar answered Oct 14 '22 20:10

epint