Android 获取 webview 高度的可靠方法

Android reliable method for getting the height of a webview

我想知道是否有人有可靠的方法在显示内容之前获取 webview 的高度。我以前见过这个问题的变体。之前的答案建议使用以下代码:

viewTreeObserver  = webview.getViewTreeObserver();
    viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
        int prevValue=0;
        @Override
        public boolean onPreDraw() {     

                int contentHeight = webview.getContentHeight();
                Log.d("PreDraw","PreDrawCalled, Content Height: " + String.valueOf(contentHeight));

                if ( contentHeight!= 0 && contentHeight==prevValue){
                    //Make sure the height has converged
                    int newPosition=(int)Math.round((webview.getContentHeight()*scrollPercent));
                    webview.scrollTo(0, newPosition);
                    webview.getViewTreeObserver().removeOnPreDrawListener(this);
                }
                prevValue=contentHeight;
                return false;
        }
        });

我添加了 prevValue 变量。我的想法是检查以确保 contentHeight 的先前值与 contentHeigh 的当前值相匹配,所以基本上我必须连续两次获得相同的高度。那甚至都行不通。下面是 LogCat.

的输出
04-05 19:24:04.851: D/PreDraw(18633): PreDrawCalled, Content Height: 0
04-05 19:24:04.853: D/PreDraw(18633): PreDrawCalled, Content Height: 0
04-05 19:24:04.867: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.882: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.898: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.915: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.932: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.949: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.966: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.982: D/PreDraw(18633): PreDrawCalled, Content Height: 2114

LogCat 显示我连续多次获得相同的 contentHeight 值,所以我无法可靠地比较以前的值,除非我 运行 在一个循环中并放入一些标准说我必须连续 10 次得到相同的答案之类的,但这感觉很老套。我希望有更好的解决方案。

总体目标是在屏幕旋转时以及重新启动 activity 时保持 webview 滚动位置。我将 scrollPercent 变量存储在数据库中。

感谢您的帮助。

webView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
          int height = webView.getHeight()
    }

}

我想我在尝试了很多没有用的方法后终于找到了解决方案。使用 onPreDraw 函数并等待内容高度不为零的问题似乎是,如果 webview 正在加载图像,内容高度可能等于某个中间值。我还尝试了 WebViewClient onPageFinished 方法,但即使页面仍在加载图像,它也会触发。我还试图覆盖我不理解的 WebView 的无效方法,但它也有同样的问题。对我有用的解决方案是实际调用 javascript 函数。 Javascript 似乎有更多方法可用于检测页面加载,其中还包括何时下载了所有内容(包括图像)。我做了以下事情:

我在 html 中添加了一个 javascript 函数。对于某些人来说,这可能不是一个选项,但我可以完全控制 html 内容。

<script>
function loadAlert() {
    var loadFlag;
    if (document.readyState === "complete") {
       loadFlag=1;

    }else{
        loadFlag=0;
    }

    window.pageload.sendToAndroid(loadFlag);
}
</script>

我不熟悉 javascript 但基本上此函数将变量 loadFlag 设置为 0(如果页面未加载)和 1(加载时)。 document.readyState 等同于加载完所有内容(包括图像)后完成。然后从 Android.

查询这个函数

以下 class 已添加到 android 项目中。这只是附加到我正在使用的文件中主要片段 class 的末尾。这段代码是从以前的 Whosebug post 修改而来的。我不太明白这一点,但它为 javascript.

设置了某种接口
    final class IJavascriptHandler {
       IJavascriptHandler() {
       }
       // This annotation is required in Jelly Bean and later:
       @JavascriptInterface
       public void sendToAndroid(int loadFlag) {
          // this is called from JS with passed value
           jsLoadFlag=loadFlag;

       }
    }

以下代码被放置在 onCreateView 中(这是一个片段)。获取webview后,启用javascript。最后一行设置上面定义的接口。

    webview = (WebView)v.findViewById(R.id.webView2);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.addJavascriptInterface(new IJavascriptHandler(), "pageload");

其余代码设置 PreDraw 侦听器。从文档中可以看出,当即将绘制视图树时会调用它,但这并不意味着所有内容都已加载。这就是为什么一些 post 建议检查 webview.getContentHeight 何时不等于零。我遇到的问题是在加载图片时我会得到一个非零数字。

第一个 if 语句检查以确保 getContentHeight 不等于零并且 webview 进度为 100,以便 webview 认为它已加载。我将 javascript 调用放在这个 if 语句中,以便最小化 javascript 调用。这也允许在屏幕旋转时 javascript 调用有一些延迟。我不确定它什么时候会在屏幕旋转时恢复为零,但这会增加一些缓冲。

jsLoadFlag 是在 javascript 接口 class 中设置的变量。它在整个文件中可见。在 onCreateView 方法中将其设置为 0 很重要,否则在旋转时可能会保留其先前的值 1。如果页面已完成加载,则此变量应该仅为 1。当 webview.getContentHeight!=0 和 webview.getProgress==100 和 jsLoadFlag==1 时,我想要 运行 的代码仅 运行s。如果满足这些条件,则页面已加载。在 IF 语句中,我然后将 webview 滚动到正确的位置。

    //Reset jsLoadFlag to account for rotations.
    jsLoadFlag=0;

    viewTreeObserver  = webview.getViewTreeObserver();
    viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {  

                if ( webview.getContentHeight()!= 0 && webview.getProgress()==100){

                    //This function sets the jsLoadFlag variable
                    webview.loadUrl("javascript:loadAlert();void(0)");


                    if(jsLoadFlag==1){

                        //Entire page including all pictures should have loaded so getContentHeight should be accurate
                        int newPosition=(int)Math.round((webview.getContentHeight()*scrollPercent));
                        webview.scrollTo(0, newPosition);

                        webview.getViewTreeObserver().removeOnPreDrawListener(this);
                    }
                }
                return false;
        }
        });