web-dev-qa-db-fra.com

Android obtient la hauteur du contenu Webview une fois rendu

J'essaie d'obtenir le maximum d'une Webview une fois qu'elle a été rendue. Il retourne toujours null, j'ai essayé getHeight, getMeasuredHeight, getContentHeight et il retourne toujours null.

Disposition:

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

Activité

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

}

Je ne sais même pas s'il est possible d'obtenir la hauteur de la vue Web après son rendu, mais je ne vois pas pourquoi vous ne pourriez pas. si quelqu'un avait des solutions, ce serait grandement apprécié.

14
Paddy1990

Vous pouvez utiliser ViewTreeObserver sur cette WebView pour obtenir la hauteur réelle après le rendu de son contenu.

voici l'exemple de 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;
                   }
           });
26
NaserShaikh

J'ai trouvé cette solution fiable à 100%.

Sous-classez votre WebView et il est nécessaire d'appeler javascript après le chargement du contenu.

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

Nous pouvons alors obtenir la bonne hauteur et désactiver javascript dans le rappel (pour des raisons de sécurité et de cohérence):

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 doit appeler post () car le code à l'intérieur de resize (...) est appelé dans le thread WebView!

Ensuite, assurez-vous de mettre à l'échelle vos pixels pour correspondre à la densité des pixels !:

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

ok, c'est bien plus tard, mais je pense que c'est une bonne solution, utilisez simplement if (webView.getContentHeight() > 0) si ture cela signifie que ça s'est terminé, sinon, ce n'est pas encore fini 

0
Xianwei

Essayé et testé les éléments suivants:

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

    });

Journaux:

12-20 16: 08: 33.969 1466-1466/yourPkg I/démo: onLayoutChange: top = 0, Bottom = 0, hauteur du contenu = 0
12-20 16: 08: 33.970 1466-1466/yourPkg I/démo: onLayoutChange: top = 0, bottom = 0, hauteur du contenu = 0
12-20 16: 08: 34.061 1466-1466/yourPkg I/demo: onLayoutChange: top = 0, Bottom = 1510, hauteur du contenu = 0
12-20 16: 08: 34.091 1466-1466/yourPkg I/démo: onLayoutChange: top = 0, bottom = 1510, hauteur du contenu = 2050

Le dernier est correct.
ViewTreeObserver m'a parfois donné une mauvaise hauteur.

0
PJ_Finnegan

J'ai choisi cette approche

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

0
Dmitriy Melekhov