Android WebView - 使用 Javascript 设置 HTML 字段焦点

发布于 2024-10-31 22:25:25 字数 6635 浏览 8 评论 0原文

我有一个应用程序,其中只有一个可见的 WebView 组件,用于显示一些动态生成的 HTML(也可以运行 Javascript)。它已针对 WebView 启用。

对于几页,我试图在页面加载完成后设置其中一个输入文本框的焦点 - 不是通过 Body onLoad(),而是通过页面加载完成后的 JS 调用,即在 onPageFinished() 中。大多数 JavaScript 执行得很好

    webview.loadURL("javascript:JSMethod();");

但是当我使用相同的调用来执行 document.getElementById('text1').focus() 时 - 光标确实到达了该元素,但 软键盘< /code> 不会弹出。从页面上的按钮执行相同的 JavaScript 代码确实会达到预期的效果。

我附上具有 3 个按钮 的源代码

  1. Focus Text1 - 将光标放在 text1 上并弹出软键盘。
  2. Java Focus Text1 - 调用Java来执行相同的JS。只显示光标,不弹出键盘
  3. Java Focus Text1 And Keyboard Open - 从 Java 调用 JS 并强制打开键盘。

我的理解是,无论是使用按钮/事件从浏览器执行还是通过 WebView.loadURL() 从 Java 发送,JS 执行的工作方式都应该相同。

这是我的查询

  1. 我在使用 Button#2 时是否遗漏了某些内容?这就是我当前的代码,我只看到光标已设置,但软键盘不会打开。
  2. 当我使用 Button#3 中编写的逻辑时,有时我在字段上看不到光标,但给了我所需的效果,并且当我在弹出的键盘中键入内容时光标变得可见。
  3. 我在 Button#2 中看到的行为是否可能是 Android JS 执行中的错误?或者可能是 WebView 没有焦点,这就是为什么只显示光标?我还尝试了 webview.requestFocus() - 我无法编写 requestFocusOnTouch() ,因为它是我拥有的唯一视图,并且期望它自动聚焦。

演示该行为的 Java 代码是

    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.inputmethod.InputMethodManager;
    import android.webkit.JsResult;
    import android.webkit.WebChromeClient;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;

    public class WebViewProjectTestJSHTMLFocusActivity extends Activity {

        Activity _current = null;
        WebView wv = null;

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            _current = this;
            //setContentView(R.layout.main);
            String data = "<html><body>" +
                                "<script>function focusser() { document.getElementById(\"text1\").focus(); } </script>" +
                                "<script>function javaFocusser() { javautil.javaFocus(false); } </script>" +
                                "<script>function javaFocusserKeyboard() { javautil.javaFocus(true); } </script>" +
                                "Text 1<input type='text' id='text1'/><br/>" +
                                "Text 2<input type='text' id='text2'/><br/>" +
                                "<input type='button' value='Focus Text1' onClick='focusser()'/>" +
                                "<input type='button' value='Java Focus Text1' onClick='javaFocusser()'/>" +
                                "<input type='button' value='Java Focus Text1 And Keyboard Open' onClick='javaFocusserKeyboard()'/>" +
                            "</body></html>";
            wv = new WebView(this);
            wv.getSettings().setJavaScriptEnabled(true);

            // Set some HTML 
            wv.loadDataWithBaseURL("file:///android_asset/", data, "text/html", "UTF-8", null);

            // Call back required after page load finished
            wv.setWebViewClient(new CustomWebViewClient());

            // Enable Alert calls  
            wv.setWebChromeClient(new CustomWebChromeClient());

            // For JS->Java calls
            wv.addJavascriptInterface(this, "javautil");

            setContentView(wv);
        }


        /**
         * Calls the same javascript and forces the keyboard to open 
         */
        public void javaFocus(final boolean shouldForceOpenKeyboard) {

            Thread t = new Thread("Java focusser thread") {
                public void run() {
                    wv.loadUrl("javascript:focusser();");
                    if(shouldForceOpenKeyboard) {
                        InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        mgr.showSoftInput(wv, InputMethodManager.SHOW_IMPLICIT);
                    }
                }
            };

            // Run on the View Thread.
            _current.runOnUiThread(t);
        }

        /**
         * Calls focus method after the page load is complete.
         */
        final class CustomWebViewClient
        extends WebViewClient {
            @Override
            public void onPageFinished(WebView view, String url) {
                // javaFocus(true);
                Log.d("TestExamples", "focusser call complete");
            }
        }

        final class CustomWebChromeClient
        extends WebChromeClient {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Log.d("TestExamples", "JS Alert :: " + message);
                return false;
            }
        }
    }

解决方案更新 24-06-2011 要实现此功能,您需要在实际 JS 焦点调用之前使用 wv.requestFocus(View.FOCUS_DOWN) 。我将上面的 javaFocus() 方法修改为下面的正确版本。早些时候,当我提到我正在使用 requestFocus() 时,我是在 onCreate() 方法中初始化 WebView 时使用的。主要区别在于,现在我们强制 WebView 每次在执行 Javascript document.getElementById("text1").focus(); 之前获得焦点。

public void javaFocus(final boolean shouldForceOpenKeyboard) {
    Thread t = new Thread("Java focusser thread") {
        public void run() {
            wv.requestFocus(View.FOCUS_DOWN);
            wv.loadUrl("javascript:focusser();");
            if(shouldForceOpenKeyboard) {
                InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                mgr.showSoftInput(wv, InputMethodManager.SHOW_IMPLICIT);
            }
        }
    };

    // Run on the View Thread.
    _current.runOnUiThread(t);
}

另外,为了确保由于通过触摸等触发焦点而导致此问题没有得到解决,我使用后台线程在 WebView 显示 5 秒后启动 javaFocus() 。修改后的 onCreate() 如下。

..... More onCreate code before....
// Enable Alert calls  
wv.setWebChromeClient(new CustomWebChromeClient());

// For JS->Java calls
wv.addJavascriptInterface(this, "javautil");

setContentView(wv);

new Thread("After sometime Focus") {
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        javaFocus(true);
    }
}.start();
.... onCreate() ends after this.... 

I have an application with just a visible WebView component to it which is used to display some dynamically generated HTML (can run Javascript too). It's enabled for the WebView.

For a few pages I am trying to set the focus of one of the input text boxes after the page load has finished - not through Body onLoad(), but instead by a JS call after the page has finished loading i.e. in onPageFinished(). Most of the javascript executes fine

    webview.loadURL("javascript:JSMethod();");

But when I use the same call to do a document.getElementById('text1').focus() - the cursor does reach the element but the Soft Keyboard won't pop out. The same javascript code when executed from a button on the page does have the desired effect.

I am attaching the source code which has 3 buttons

  1. Focus Text1 - Put the cursor on the text1 and pops up the Softkeyboard.
  2. Java Focus Text1 - Calls Java to execute the same JS. Only shows the cursor there and doesn't pop out the keyboard
  3. Java Focus Text1 And Keyboard Open - Calls JS from Java and Forces Keyboard open.

My understanding is that the JS execution should work the same whether executed from the browser using a button/event or as sent from Java through WebView.loadURL().

Here's my Queries

  1. Am I missing something when using Button#2? That's how my current code is and I only see the cursor is set but the SoftKeyboard won't open.
  2. When I use logic as written in Button#3, I some times don't see the cursor on the field but gives me the desired effect and the cursor becomes visible when I type something in the popped up keyboard.
  3. Could the behavior I see in Button#2 be a bug in Android JS execution? Or could it be that the WebView doesn't have focus that's why only the cursor is displayed? I also tried webview.requestFocus() - I can't write requestFocusOnTouch() as it's the only View I have and am expecting it's focused automatically.

The Java code which demos the behavior is

    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.inputmethod.InputMethodManager;
    import android.webkit.JsResult;
    import android.webkit.WebChromeClient;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;

    public class WebViewProjectTestJSHTMLFocusActivity extends Activity {

        Activity _current = null;
        WebView wv = null;

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            _current = this;
            //setContentView(R.layout.main);
            String data = "<html><body>" +
                                "<script>function focusser() { document.getElementById(\"text1\").focus(); } </script>" +
                                "<script>function javaFocusser() { javautil.javaFocus(false); } </script>" +
                                "<script>function javaFocusserKeyboard() { javautil.javaFocus(true); } </script>" +
                                "Text 1<input type='text' id='text1'/><br/>" +
                                "Text 2<input type='text' id='text2'/><br/>" +
                                "<input type='button' value='Focus Text1' onClick='focusser()'/>" +
                                "<input type='button' value='Java Focus Text1' onClick='javaFocusser()'/>" +
                                "<input type='button' value='Java Focus Text1 And Keyboard Open' onClick='javaFocusserKeyboard()'/>" +
                            "</body></html>";
            wv = new WebView(this);
            wv.getSettings().setJavaScriptEnabled(true);

            // Set some HTML 
            wv.loadDataWithBaseURL("file:///android_asset/", data, "text/html", "UTF-8", null);

            // Call back required after page load finished
            wv.setWebViewClient(new CustomWebViewClient());

            // Enable Alert calls  
            wv.setWebChromeClient(new CustomWebChromeClient());

            // For JS->Java calls
            wv.addJavascriptInterface(this, "javautil");

            setContentView(wv);
        }


        /**
         * Calls the same javascript and forces the keyboard to open 
         */
        public void javaFocus(final boolean shouldForceOpenKeyboard) {

            Thread t = new Thread("Java focusser thread") {
                public void run() {
                    wv.loadUrl("javascript:focusser();");
                    if(shouldForceOpenKeyboard) {
                        InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        mgr.showSoftInput(wv, InputMethodManager.SHOW_IMPLICIT);
                    }
                }
            };

            // Run on the View Thread.
            _current.runOnUiThread(t);
        }

        /**
         * Calls focus method after the page load is complete.
         */
        final class CustomWebViewClient
        extends WebViewClient {
            @Override
            public void onPageFinished(WebView view, String url) {
                // javaFocus(true);
                Log.d("TestExamples", "focusser call complete");
            }
        }

        final class CustomWebChromeClient
        extends WebChromeClient {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Log.d("TestExamples", "JS Alert :: " + message);
                return false;
            }
        }
    }

Solution Update 24-06-2011
To make this work, you need to use wv.requestFocus(View.FOCUS_DOWN) just before the actual JS focus call. I modified the javaFocus() method above to the correct version below. Earlier when I mentioned that I was using requestFocus(), I was using that when the WebView was initialized in the method onCreate(). The primary difference is now we're forcing the WebView to get focus each time just before the Javascript document.getElementById("text1").focus(); is executed.

public void javaFocus(final boolean shouldForceOpenKeyboard) {
    Thread t = new Thread("Java focusser thread") {
        public void run() {
            wv.requestFocus(View.FOCUS_DOWN);
            wv.loadUrl("javascript:focusser();");
            if(shouldForceOpenKeyboard) {
                InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                mgr.showSoftInput(wv, InputMethodManager.SHOW_IMPLICIT);
            }
        }
    };

    // Run on the View Thread.
    _current.runOnUiThread(t);
}

Also to ensure that this issue wasn't fixed because of focus triggered through touch etc, I am using a background thread to initiate the javaFocus() after 5 seconds of WebView Displayed. The modified onCreate() is below.

..... More onCreate code before....
// Enable Alert calls  
wv.setWebChromeClient(new CustomWebChromeClient());

// For JS->Java calls
wv.addJavascriptInterface(this, "javautil");

setContentView(wv);

new Thread("After sometime Focus") {
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        javaFocus(true);
    }
}.start();
.... onCreate() ends after this.... 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

记忆之渊 2024-11-07 22:25:25

可能是 Web 视图没有应用程序焦点。尝试执行;

wv.requestFocus(View.FOCUS_DOWN);

It could be that the webview doesn't have the application focus. Try executing;

wv.requestFocus(View.FOCUS_DOWN);
蓝海 2024-11-07 22:25:25

这是完整的解决方案。

protected void onCreate(Bundle savedInstanceState) {

    // setfocus on page load finished
    myWebView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(myWebView, url);
            myWebView.requestFocus(View.FOCUS_DOWN);
            Toast.makeText(getApplicationContext(), "Done!", Toast.LENGTH_SHORT).show();
        }
    });
}

Here is the complete solution.

protected void onCreate(Bundle savedInstanceState) {

    // setfocus on page load finished
    myWebView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(myWebView, url);
            myWebView.requestFocus(View.FOCUS_DOWN);
            Toast.makeText(getApplicationContext(), "Done!", Toast.LENGTH_SHORT).show();
        }
    });
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文