用于获取webview高度的Android可靠方法

时间:2015-04-05 23:37:00

标签: android webview height

我想知道在显示内容之前是否有人有可靠的方法来获取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次连续的东西,但感觉hacky。我希望有更好的解决方案。

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

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

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

}

答案 1 :(得分:0)

我认为在尝试了一些不起作用的事情之后我终于找到了解决方案。似乎使用onPreDraw函数并等待内容高度不等于零的问题是,如果webview正在加载图像,则内容高度可能等于某个中间值。我也尝试过onPageFinished的WebViewClient方法,但即使页面仍在加载图像,也会触发。我还尝试覆盖WebView的invalidate方法,我不明白但也有同样的问题。对我有用的解决方案是实际调用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查询此功能。

以下类被添加到android项目中。这只是附加到我正在使用的文件中的主片段类的末尾。这段代码是从之前的Stackoverflow帖子修改而来的。我不太明白这一点,但它为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监听器。从文档中,在将要绘制视图树时调用它,但这并不意味着加载了所有内容。这就是为什么有些帖子建议检查webview.getContentHeight何时不等于零的原因。我遇到的问题是,当图片加载时,我会得到一个非零数字。

第一个if语句检查以确保getContentHeight不等于零,并且webview进度为100,因此webview认为它已加载。我把javascript调用放在这个if语句中,以便最小化javascript调用。这也允许在旋转屏幕时对javascript调用进行一些延迟。我不确定在屏幕旋转时它究竟会被设置回零,但这会增加一些缓冲。

jsLoadFlag是一个在javascript接口类中设置的变量。它在整个文件中都可见。在onCreateView方法中将其设置为0很重要,否则在旋转时可能会保留它的先前值1.如果页面已完成加载,则此变量应该只为1。我想运行的代码仅在webview.getContentHeight!= 0和webview.getProgress == 100和jsLoadFlag == 1时运行。如果满足这些条件,则页面已加载。在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;
        }
        });