Java Android 在呈现后获取 webview 内容的高度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22878069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 18:37:53  来源:igfitidea点击:

Android get height of webview content once rendered

javaandroidwebview

提问by Paddy1990

I'm trying to get the height of a webview once it has been rendered. It always returns null, I've tried getHeight, getMeasuredHeight, getContentHeightand it always returns null.

我试图在渲染后获取 webview 的高度。它总是返回null,我试过getHeightgetMeasuredHeightgetContentHeight它总是返回null。

Layout:

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/instructions"
    android:background="@color/transparent_black" >

        <WebView
            android:id="@+id/top_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </RelativeLayout>

Activity

活动

public class TestActivity extends MenuActivity {

private final static String TAG = "HearingTest";
private String urlTopContent;
private WebView topContent;
private boolean mMoreInfoTop = true;
private int mYdelta = 0;
private int mBottomOffset = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.right_hearing_test);

        String topHtml = this.getString(R.string.top_content);
        //String bottomHtml = this.getString(R.string.bottom_content);

        urlTopContent = "file:///android_asset/html/" + topHtml;
        WebViewSettings();
        LoadWebPage(urlTopContent);
    }

    public void WebViewSettings(){

        topContent = (WebView) findViewById(R.id.top_content);
        topContent.getSettings().setJavaScriptEnabled(true);
        topContent.getSettings().setBuiltInZoomControls(true);
        topContent.getSettings().setSupportZoom(true);
        topContent.getSettings().setLoadWithOverviewMode(true);
        topContent.setBackgroundColor(0);
        topContent.canGoBack();

        int topHeight = topContent.getContentHeight();
        Log.d("Top Height", "Height: " + topHeight);            

        topContent.setWebViewClient(new WebViewClient(){

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (Uri.parse(url).getHost().equals(urlTopContent)) {
                    // This is my web site, so do not override; let my WebView load the page
                    return false;
                }
                // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                startActivity(intent);
                return true;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                View webViewHeight = (View) findViewById(R.id.top_content);
                int height = webViewHeight.getHeight();
                Log.d("Top Content","Top Content Height:" + height);
            }
        });
    }

    public void LoadWebPage(String url){

        try {
            topContent.loadUrl(url);
            Log.d("Loading Web Page", "URL" + url + "connected");
        } 
        catch (Exception e) {
                Log.d("Loading Web Page", "URL: " + url + " couldn't connect.");
        }
    }

}

I don't even know if it's possible to get the height of the web view after it has rendered but I don't see why you couldn't. if anyones got and solutions it would be greatly appreciated.

我什至不知道是否有可能在呈现后获得 web 视图的高度,但我不明白为什么你不能。如果有人得到和解决方案,将不胜感激。

采纳答案by NaserShaikh

You can use ViewTreeObserveron that WebViewto get actual height after rendering its content.

您可以在渲染其内容后使用ViewTreeObserverWebView来获取实际高度。

here's the sample code.

这是示例代码。

ViewTreeObserver viewTreeObserver  = mWebView.getViewTreeObserver();

viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
                   @Override
                   public boolean onPreDraw() {                                
                           int height = mWebView.getMeasuredHeight();
                           if( height != 0 ){
                                   Toast.makeText(getActivity(), "height:"+height,Toast.LENGTH_SHORT).show();
                                   mWebView.getViewTreeObserver().removeOnPreDrawListener(this);
                           }
                           return false;
                   }
           });

回答by PJ_Finnegan

Tried and tested the following:

尝试并测试了以下内容:

    mWebView = new WebView(this);
    mWebView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {

        @Override
        public void onLayoutChange(View view, int l, int t, int r, int b, int ol, int ot, int or, int ob) {
            Log.i("demo", String.format("%s: top=%d, bottom=%d, content height=%d",
                    Thread.currentThread().getStackTrace()[2].getMethodName(), t, b, mWebView.getContentHeight()
            ));
        }

    });

Logs:

日志:

12-20 16:08:33.969 1466-1466/yourPkg I/demo: onLayoutChange: top=0, bottom=0, content height=0
12-20 16:08:33.970 1466-1466/yourPkg I/demo: onLayoutChange: top=0, bottom=0, content height=0
12-20 16:08:34.061 1466-1466/yourPkg I/demo: onLayoutChange: top=0, bottom=1510, content height=0
12-20 16:08:34.091 1466-1466/yourPkg I/demo: onLayoutChange: top=0, bottom=1510, content height=2050

12-20 16:08:33.969 1466-1466/yourPkg I/demo: onLayoutChange: top=0, bottom=0, content height=0
12-20 16:08:33.970 1466-1466/yourPkg I/demo: onLayoutChange顶部=0,底部=0,内容高度=0
12-20 16:08:34.061 1466-1466/yourPkg I/demo:onLayoutChange:顶部=0,底部=1510,内容高度=0
12-20 16:08: 34.091 1466-1466/yourPkg I/demo:onLayoutChange:顶部=0,底部=1510,内容高度=2050

The last one is correct.
ViewTreeObserversometimes gave me the wrong height.

最后一个是正确的。
ViewTreeObserver有时给我错误的高度。

回答by Micha? Dobi Dobrzański

I found this solution to be 100% reliable.

我发现这个解决方案是 100% 可靠的。

Subclass your WebView and there is a need to invoke javascriptafter the content has been loaded.

将您的 WebView 子类化,并且需要在加载内容后调用javascript

// callback made this way in order to get reliable html height and to avoid race conditions
    @SuppressLint("SetJavaScriptEnabled")
    override fun onPageFinished(view: WebView?, url: String?) {
        view?.let {
            it.settings.javaScriptEnabled = true
            it.addJavascriptInterface(WebAppInterface(it), "AndroidGetHeightFunction")
            it.loadUrl("javascript:AndroidGetHeightFunction.resize(document.body.scrollHeight)")
        }
    }

We can then get proper height and disable javascript in callback(for security and consistency):

然后我们可以获得适当的高度并在回调中禁用 javascript(为了安全和一致性):

inner class WebAppInterface(private val webView: WebView) {
    @JavascriptInterface
    fun resize(height: Float) {
        webView.post {
            heightMeasuredListener?.invoke(formatContentHeight(webView, height.toInt()))
            webView.settings.javaScriptEnabled = false
        }
    }
}

WebView must call post()as the code inside resize(...) is called in WebView thread!

WebView必须调用 post()作为 resize(...) 中的代码在 WebView 线程中调用!

After, make sure to scale your pixels to match density pixels!:

之后,确保缩放像素以匹配密度像素!:

fun formatContentHeight(webView: WebView, height: Int): Int = Math.floor((height * webView.context.resources.displayMetrics.density).toDouble()).toInt()

回答by Xianwei

ok, this is pretty later, but I think it nice solution, just use if (webView.getContentHeight() > 0)if tureit means it finsihed, else, it not finished yet

好的,这已经很晚了,但我认为这是一个不错的解决方案,if (webView.getContentHeight() > 0)如果ture这意味着它完成了就使用它,否则,它还没有完成

回答by Dmitriy Melekhov

I chose this approach

我选择了这种方法

const val heightWebViewJSScript = "(function() {var pageHeight = 0;function findHighestNode(nodesList) { for (var i = nodesList.length - 1; i >= 0; i--) {if (nodesList[i].scrollHeight && nodesList[i].clientHeight) {var elHeight = Math.max(nodesList[i].scrollHeight, nodesList[i].clientHeight);pageHeight = Math.max(elHeight, pageHeight);}if (nodesList[i].childNodes.length) findHighestNode(nodesList[i].childNodes);}}findHighestNode(document.documentElement.childNodes); return pageHeight;})()"

webView.webViewClient = object : WebViewClient() {

            override fun onPageFinished(view: WebView, url: String) {
                webView.evaluateJavascript(heightWebViewJSScript
                ) { height ->
                    val params = itemView.layoutParams
                    // params.height
                }
            }
        }