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--;
}
}
});
}
}
總結
以上是我針對該類問題想到的一些處理方案,大家有更好的處理方式不妨也分享一下,集思廣路,一同進步。