WebView高度自適應方案探究

Android項目開發中針對webview避免不了混合開發模式,可Android上的webview又很不爭氣,幾乎每個Android版本都有webvie的改動,在國內這種魚龍混雜環境下出乎意料的問題又很多,這次就談談webview高度自適應的問題。

問題

在Android開發生涯中想必大家都遇到過,webview在有些時候展示不完整,在某些時候底部有一片空白,有些時候始終又滑不到底。。。導致這個問題的原因常見有以下三種:

  • 網頁高度不固定
  • 嵌套佈局導致webview的高度無法自適應
  • 系統原因導致webview在某種特殊情況下不能兼容當前應用的屏幕分辨率

下邊就分別說說這三種情況引起的原因以及解決方法。

針對網頁高度不固定問題

這部分原因和H5編寫方法有很大關係,例如Ajax異步處理結果過慢,webview的高度不能及時更新;也有可能H5編寫時預留了一個資源展示區等待將來資源展示,結果資源沒有加載出來。這個和H5開發人員說明一下情況,檢查一下代碼結構。

針對嵌套佈局導致webview高度不固定問題

這個是Android開發最常見的事,很多時候是混合開發模式,不得已採用scrollview嵌套webview,但是我們知道scrollview中嵌套其他view常常使某些view的高度(match_parent)失效,當然你可以採用android:fillViewport="true"強制讓其撐滿,但是似乎其內部的webview又不聽話了,這個道理很明顯,畢竟webview渲染的是網頁,也即是我們能夠準確固定webview高度這個問題就迎刃而解了。

針對webview兼容當前應用屏幕密度問題

首先我們要處理的是避免系統字體的縮放影響webview縮放,我們可以用webview.getSettings().setTextZoom(100)來避免。其餘的支持自適應即可,在應用屏幕密度設定之後webiview可自動匹配,當然也有一些奇葩設備(被應用商修改過),這部分我們可以忽略了。

針對高度不固定問題解決方案

我這裏給出兩種解決方案。

佈局結構調整

按照官方建議webiview父佈局高度採用match_parent

WebView根據網頁的高度自動擴展自身高度:

我們按照步驟走:

第一步:本地定義Js交互接口,通常H5需要明確這個接口標識,Android端才能回調相關內容給H5。

mWebView.addJavascriptInterface(this, "App");

第二步:本地實現接口方法,H5通過上邊的“APP”接口標識能調用本地該接口裏面的方法。

/**
 * js回調,重新計算webview的高度。
 */
@JavascriptInterface
public void resize(final float clientWidth, final float scrollHeight) {
    if (mActivity == null || mWebView == null || clientWidth == 0) {
        return;
    }
    mActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            float rate = mWebView.getWidth() / clientWidth;
            Log.i("TAG", "webview---------clientWidth:" + clientWidth + "---------scrollHeight:" + scrollHeight + "---------rate:" + rate);
            mWebView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                    (int) (scrollHeight * rate)));
        }
    });
}

第三步:本地調用H5的js方法,告訴H5:“我,大Android,需要你H5現在的寬和高”,然後H5乖乖的把界面上寬高回調給本地,就是第二步的方法。但是!我今天說的這個是通用方式,是針對所有的H5的,不可能讓每個H5都定義一個js方法供Android端調用,怎麼辦呢?好辦,直接讓H5回調本地方法:

mWebView.loadUrl("javascript:App.resize(document.documentElement.clientWidth, document.documentElement.scrollHeight)");

這裏的“App”其實就是“this”,那麼js回調時機是什麼時候呢,我是希望這個頁面加載結束的時候告訴我,所以重寫WebViewClient裏面的onPageFinished方法。由於有些H5採用異步加載的方式,我不知道他到底什麼時候完全加載出來,所以這裏我分多次讓H5幫我回調:

class DefaultWebViewClient extends WebViewClient {

    //頁面內跳轉
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String s) {
        webView.loadUrl(s);
        return true;
    }

    @Override
    public void onPageFinished(WebView webView, String s) {
        super.onPageFinished(webView, s);

        //執行網頁高度獲取,不斷獲取網頁高度
        mHandler.post(new Runnable() {

            //執行最大次數
            int times = 5;

            @Override
            public void run() {
                if (times > 0) {
                    mWebView.loadUrl("javascript:App.resize(document.documentElement.clientWidth, document.documentElement.scrollHeight)");
                    mHandler.postDelayed(this, 1000);
                    times--;
                }
            }
        });
    }
}

總結

以上是我針對該類問題想到的一些處理方案,大家有更好的處理方式不妨也分享一下,集思廣路,一同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章