【问题标题】:Android reliable method for getting the height of a webviewAndroid获取webview高度的可靠方法
【发布时间】:2015-06-10 09:20:59
【问题描述】:

我想知道是否有人有可靠的方法在显示内容之前获取 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。我希望有更好的解决方案。

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

感谢您的帮助。

【问题讨论】:

    标签: android webview height


    【解决方案1】:

    我想我在尝试了很多不起作用的事情后终于找到了解决方案。似乎使用 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 中查询此函数。

    以下类已添加到 android 项目中。这只是附加到我正在使用的文件中主要片段类的末尾。这个 sn-p 代码是从以前的 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 不等于 0 并且 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;
            }
            });
    

    【讨论】:

    • 什么是滚动百分比?
    • scrollPercent 是 webView 高度的百分比。该值在用户旋转之前记录。该变量用于在旋转后返回同一位置。
    【解决方案2】:
    webView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
              int height = webView.getHeight()
        }
    
    }
    

    【讨论】:

    • 我遇到了与 PreDrawListener 相同的问题。部分问题似乎是我在 webview 中有图像,它们需要一些时间才能加载,这导致侦听器使用不同的内容高度值多次触发。
    • 一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。 (该帖子至少被一位用户标记,大概是因为他们认为应该删除没有解释的答案。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    相关资源
    最近更新 更多