如何獲取WebView內(nèi)容高度

序言

最近項(xiàng)目需求中需要實(shí)現(xiàn)WebView顯示內(nèi)容瞪醋,下方顯示評(píng)論列表,列表還可以分頁加載践盼。我最近做了技術(shù)預(yù)研宾巍,難度主要是實(shí)時(shí)獲取WebView的高度。

效果

1.分頁加載

這里寫圖片描述

2.動(dòng)態(tài)獲取高度顶霞,點(diǎn)擊閱讀更多,會(huì)將幾個(gè)隱藏的div蓝厌,顯示出來,造成WebView內(nèi)容高度變化拓提。

這里寫圖片描述

實(shí)現(xiàn)

使用的ScrollView包裹一層LinearLayout隧膘,LinearLayout中依次防止WebView和RecyclerView寺惫。布局如下:

<?xml version="1.0" encoding="utf-8"?>
<com.trs.studyview.view.TRSScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.trs.studyview.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.trs.studyview.view.TRSWebView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="100dp" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</com.trs.studyview.view.TRSScrollView>

問題一西雀,如果獲取WebView高度

1.通過js獲取

以下是js獲取高度的方法

網(wǎng)頁可見區(qū)域?qū)挘?document.body.clientWidth 
網(wǎng)頁可見區(qū)域高: document.body.clientHeight 
網(wǎng)頁可見區(qū)域?qū)挘?document.body.offsetWidth (包括邊線的寬) 
網(wǎng)頁可見區(qū)域高: document.body.offsetHeight (包括邊線的高) 
網(wǎng)頁正文全文寬: document.body.scrollWidth 
網(wǎng)頁正文全文高: document.body.scrollHeight 
網(wǎng)頁被卷去的高: document.body.scrollTop 
網(wǎng)頁被卷去的左: document.body.scrollLeft 
網(wǎng)頁正文部分上: window.screenTop 
網(wǎng)頁正文部分左: window.screenLeft 
屏幕分辨率的高: window.screen.height 
屏幕分辨率的寬: window.screen.width 
屏幕可用工作區(qū)高度: window.screen.availHeight 
屏幕可用工作區(qū)寬度: window.screen.availWidth 

下面是測試代碼

package com.trs.studyview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.trs.studyview.adpater.CommentAdapter;
import com.trs.studyview.view.TRSScrollView;
import com.trs.studyview.view.TRSWebView;

public class MainActivity extends AppCompatActivity {
    TRSWebView webView;
    RecyclerView recyclerView;
    String url = "http://app.nxnews.net/ningxia/cfwz/zt/201708/t20170807_1859270.html";
    CommentAdapter adapter;
    TRSScrollView scrollView;
    Mobile mobile = new Mobile();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }


    private void initView() {
        scrollView = $(R.id.scrollView);
        webView = $(R.id.webview);
        recyclerView = $(R.id.recyclerView);
        WebSettings setting = webView.getSettings();
        setting.setJavaScriptEnabled(true);//支持js
        webView.addJavascriptInterface(mobile, "mobile");
        webView.setWebViewClient(mClient);
        webView.loadUrl(url);
        adapter = new CommentAdapter();
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        scrollView.setRecyclerView(recyclerView);
    }

    private class Mobile {
        @JavascriptInterface
        public void onGetWebContentHeight(String type, int height) {
            Log.i("zzz", "onGetWebContentHeight type=" + type + " height=" + height);

        }
    }

    private String[] getHeightJs = new String[]{
            "document.body.clientHeight",
            "document.body.offsetHeight",
            "document.body.scrollHeight",
            "document.body.scrollTop",
            "window.screen.availHeight"
    };

    private WebViewClient mClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            for (int i = 0; i < getHeightJs.length; i++) {
                String js = "javascript:mobile.onGetWebContentHeight(\"" + getHeightJs[i] + "\"," + getHeightJs[i] + ")";
                view.loadUrl(js);
            }
        }
    };

    protected <T extends View> T $(int id) {
        return (T) findViewById(id);
    }
}

結(jié)果如下:

這里寫圖片描述

可以告訴大家以上高度都不對蒋搜。

2.通過getContentHeight()獲取高度

思路是在網(wǎng)頁加載完成以后通過WebView的getContentHeight()方法獲取高度
代碼如下:

    private WebViewClient mClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            Log.i("zzz", "webview contentHeight=" + view.getContentHeight());
        }
    };

運(yùn)行結(jié)果

這里寫圖片描述

結(jié)論:高度不對

3.通過measure()進(jìn)行測量

思路,在WebView加載網(wǎng)頁完畢以后育谬,通過webview.measure(0,0)進(jìn)行測量,兩個(gè)0表示對寬高無限制锰镀。

代碼改動(dòng)部分


    private class Mobile {
        @JavascriptInterface
        public void onGetWebContentHeight() {
            //重新調(diào)整webview高度
            webView.post(() -> {
                webView.measure(0, 0);
                int measuredHeight = webView.getMeasuredHeight();
                Log.i("zzz", "measuredHeight=" + measuredHeight);
            });


        }
    }


    private WebViewClient mClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            mobile.onGetWebContentHeight();
        }
    };

運(yùn)行結(jié)果

這里寫圖片描述

結(jié)論:大家可以看到這個(gè)高度是最高的咖刃,也的確是webView網(wǎng)頁內(nèi)容的高度。

總結(jié)

至此大家以后就知道怎么獲取WebView內(nèi)容高度了

問題二嚎杨,如果監(jiān)聽網(wǎng)頁高度變化

這是第一次打開APP的時(shí)候,獲取到網(wǎng)頁高度刨肃,在重新設(shè)置webView的高度,和RecyclerView的高度
代碼如下


    private class Mobile {
        @JavascriptInterface
        public void onGetWebContentHeight() {
            //重新調(diào)整webview高度
            webView.post(() -> {
                webView.measure(0, 0);
                int measuredHeight = webView.getMeasuredHeight();
                ViewGroup.LayoutParams layoutParams = webView.getLayoutParams();
                layoutParams.height = measuredHeight;
                webView.setLayoutParams(layoutParams);
                ViewGroup.LayoutParams layoutParams1 = recyclerView.getLayoutParams();
                layoutParams1.height = scrollView.getHeight();
                Log.i("zzz", "scrollView height=" + scrollView.getHeight());
                recyclerView.setLayoutParams(layoutParams1);
            });


        }
    }


    private WebViewClient mClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            mobile.onGetWebContentHeight();
        }
    };

效果如下:可以看到網(wǎng)頁全部顯示了真友,這已經(jīng)滑動(dòng)到網(wǎng)頁的最底部紧帕。

這里寫圖片描述

但問題是點(diǎn)擊閱讀更多,網(wǎng)頁中有幾個(gè)隱藏的新聞被顯示出來愈案,造成網(wǎng)頁內(nèi)容高度變化,但是我們檢測不到網(wǎng)頁內(nèi)容高度變化刻帚,所以變成這樣了。

這里寫圖片描述

下面是我的解決思路崇众。

思路1.通過js監(jiān)聽內(nèi)容變化

我通過設(shè)置window的resize監(jiān)聽來實(shí)現(xiàn)高度變化的監(jiān)聽。下面使用瀏覽器來測試:

這里寫圖片描述

結(jié)果點(diǎn)擊閱讀更多顷歌,沒有觸發(fā)相關(guān)的函數(shù)。只有調(diào)整window大學(xué)的時(shí)候才會(huì)


這里寫圖片描述

思路2.在WebView的onDraw方法中監(jiān)聽

經(jīng)過我的實(shí)驗(yàn)在點(diǎn)擊閱讀更多以后webView的contentHeight會(huì)發(fā)生變化芹扭,于是我就擴(kuò)展了WebView使其能監(jiān)聽內(nèi)容高度變化

這是我的自定義WebView:

package com.trs.studyview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebView;

/**
 * Created by zhuguohui on 2017/8/8.
 */

public class TRSWebView extends WebView {
    private int lastContentHeight = 0;
    private static final int MSG_CONTENT_CHANGE = 1;
    private onContentChangeListener onContentChangeListener = null;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_CONTENT_CHANGE:
                    if (onContentChangeListener != null) {
                        onContentChangeListener.onContentChange();
                    }
                    break;
            }
        }
    };


    public TRSWebView(Context context) {
        this(context, null);
    }

    public TRSWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (getContentHeight() != lastContentHeight) {
            handler.sendEmptyMessage(MSG_CONTENT_CHANGE);
            lastContentHeight = getContentHeight();
            Log.i("www", "contentChange height=" + getContentHeight());
        }

    }

    public void setOnContentChangeListener(TRSWebView.onContentChangeListener onContentChangeListener) {
        this.onContentChangeListener = onContentChangeListener;
    }

    /**
     * 監(jiān)聽內(nèi)容高度發(fā)生變化
     */
    public interface onContentChangeListener {
        void onContentChange();
    }
}

點(diǎn)擊多次閱讀更多

這里寫圖片描述

結(jié)論:可以監(jiān)聽網(wǎng)頁內(nèi)容的變化

問題三 recyclerView的滑動(dòng)沖突舱卡。

我是通過自定義ScrollView來實(shí)現(xiàn)的队萤,具體代碼如下,測試可用

package com.trs.studyview.view;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

/**
 * Created by zhuguohui on 2017/8/8.
 */

public class TRSScrollView extends ScrollView {
    RecyclerView recyclerView;

    public TRSScrollView(Context context) {
        this(context, null);
    }

    public TRSScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public void setRecyclerView(RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
    }

    int downY;
    int moveY = 0;
    MotionEvent downEvent;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //如果RecyclerView
        if (recyclerView != null) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downEvent = ev;
                    downY = (int) ev.getX();
                    moveY = 0;
                    break;
                case MotionEvent.ACTION_MOVE:
                    int moveY = (int) ev.getY() - downY;
                    if (Math.abs(moveY) > 20) {
                        //表示滑動(dòng)
                        if (moveY > 0) {
                            //向下滑動(dòng),如果recyclerView還沒有顯示則攔截事件
                            if (getScrollY() < recyclerView.getTop()) {
                                return true;
                            }
                        } else {
                            //向上滑動(dòng)
                            if (getScrollY() == recyclerView.getTop()) {
                                //如果第一個(gè)item已經(jīng)顯現(xiàn)才攔截事件
                                LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                                if (layoutManager.findFirstVisibleItemPosition() == 0) {
                                    return true;
                                }
                            }
                        }
                    }
                    break;
            }
        }

        return super.onInterceptTouchEvent(ev);
    }
}

最終運(yùn)行代碼

package com.trs.studyview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.trs.studyview.adpater.CommentAdapter;
import com.trs.studyview.view.TRSScrollView;
import com.trs.studyview.view.TRSWebView;

public class MainActivity extends AppCompatActivity {
    TRSWebView webView;
    RecyclerView recyclerView;
    String url = "http://app.nxnews.net/ningxia/cfwz/zt/201708/t20170807_1859270.html";
    CommentAdapter adapter;
    TRSScrollView scrollView;
    Mobile mobile = new Mobile();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }


    private void initView() {
        scrollView = $(R.id.scrollView);
        webView = $(R.id.webview);
        recyclerView = $(R.id.recyclerView);
        WebSettings setting = webView.getSettings();
        setting.setJavaScriptEnabled(true);//支持js
        webView.addJavascriptInterface(mobile, "mobile");
        // webView.setWebViewClient(mClient);
        webView.setOnContentChangeListener(() -> {
            mobile.onGetWebContentHeight();
        });
        webView.loadUrl(url);
        adapter = new CommentAdapter();
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        scrollView.setRecyclerView(recyclerView);
    }

    private class Mobile {
        @JavascriptInterface
        public void onGetWebContentHeight() {
            //重新調(diào)整webview高度
            webView.post(() -> {
                webView.measure(0, 0);
                int measuredHeight = webView.getMeasuredHeight();
                ViewGroup.LayoutParams layoutParams = webView.getLayoutParams();
                layoutParams.height = measuredHeight;
                webView.setLayoutParams(layoutParams);
                ViewGroup.LayoutParams layoutParams1 = recyclerView.getLayoutParams();
                layoutParams1.height = scrollView.getHeight();
                Log.i("zzz", "scrollView height=" + scrollView.getHeight());
                recyclerView.setLayoutParams(layoutParams1);
            });

        }
    }

    private WebViewClient mClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
        }
    };

    protected <T extends View> T $(int id) {
        return (T) findViewById(id);
    }
}

總結(jié)

這個(gè)需求難度在于知識(shí)的廣度,例如對JavaScript的熟悉程度既绩,對View事件攔截的理解还惠。研究的過程很有趣,克服重重困難吸重,完成任務(wù)的感覺很不錯(cuò)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嚎幸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嫉晶,更是在濱河造成了極大的恐慌,老刑警劉巖替废,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诈火,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)冷守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門刀崖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亮钦,“玉大人,你說我怎么就攤上這事蜂莉。” “怎么了映穗?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵淮菠,是天一觀的道長。 經(jīng)常有香客問我合陵,道長澄阳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任碎赢,我火速辦了婚禮,結(jié)果婚禮上肮塞,老公的妹妹穿的比我還像新娘。我一直安慰自己枕赵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布开皿。 她就那樣靜靜地躺著,像睡著了一般赋荆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上懊昨,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音嫉你,去河邊找鬼月帝。 笑死均抽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的油挥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼攘乒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了则酝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤沽讹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后爽雄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挚瘟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乘盖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡订框,死狀恐怖监氢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浪腐,我是刑警寧澤纵揍,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布议街,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏骨杂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一搓蚪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丁鹉,春花似錦、人聲如沸揣钦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宇姚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浑劳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工呀洲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啼止,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓献烦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巩那。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容