web-dev-qa-db-ja.com

AndroidレンダリングされたWebviewコンテンツの高さを取得

レンダリングされたWebビューの高さを取得しようとしています。常にnullを返します。私はgetHeightgetMeasuredHeightgetContentHeightを試しましたが、常にnullを返します。

レイアウト:

<?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>

アクティビティ

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.");
        }
    }

}

レンダリング後にWebビューの高さを取得できるかどうかさえわかりませんが、なぜ表示できなかったのかわかりません。誰かが解決策を手に入れたら、それは非常に高く評価されます。

18
Paddy1990

そのViewTreeObserverWebViewを使用して、コンテンツをレンダリングした後に実際の高さを取得できます。

これがサンプルコードです。

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;
                   }
           });
32
NaserShaikh

このソリューションは100%信頼できることがわかりました。

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)")
        }
    }

次に、適切な高さとコールバックで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 post()を呼び出す必要があります resize(...)内のコードがWebViewスレッドで呼び出されるため!

その後、必ずピクセルをスケーリングしてください密度ピクセルに合わせるため !:

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

私はこのアプローチを選びました

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
                }
            }
        }
1

わかりました、これはかなり遅いですが、いい解決策だと思います。if (webView.getContentHeight() > 0)を使用してくださいtureは、正常に終了したことを意味します。

0
Xianwei

以下を試してテストしました:

    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()
            ));
        }

    });

ログ:

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 = 205

最後は正解です。
ViewTreeObserverは時々私に間違った高さを与えました。

0
PJ_Finnegan