有时项目中会遇到一些比较奇葩的需求,像最近,ScrollView里面首先放一个原生的广告轮播图,再嵌入一个WebView显示H5页面。这里不讨论为什么要这么做,总有些历史原因导致。需求很简单,层级关系就只是如下而已:
很简单是吧,然后也出现一个奇怪的现象,每次WebView刷新完数据的时候,WebView都会顶到页面最上方,这个时候轮播图就看不到了,google百度查了一下,原来是WebView获取到焦点时自动滚动到页面顶部的问题,那既然是焦点问题,我们就不让WebView获取到焦点不就行了,解决方法如下,只要在WebView父窗器(即上方的LinearLayout)的属性里面添加如下属性即可:
android:descendantFocusability="blocksDescendants"
关于这个属性,我们可以查看下ViewGroup里面的介绍,截图如下:
或者你也可以直接看官网API介绍(ViewGroup API)
而我们使用的这个属性值“blocksDescendants”,作用就是让父容器阻止子容器获得焦点。
WebView嵌套在ScrollView中时,我们使用了android:layout_height=”match_parent”,但是它的高度并没有准确了,有时WebView少显示了一些数据,有时嘛,又显示了一大片空白。如何处理这个问题呢?在项目中,我使用的是通过JS获取网页的高度,然后再回传到原生App,再重新设置WebView的高度。当然,这里也涉及了Android原生与JS的相互调用。
1)获取网页的高度
我们可以在JS代码里面onload方法获取网页的高度
window.onload = function() {
window.java.resize($("body").outerHeight());
}
当然我们也可以在WebView的onPageFinish里面获取网页高度
mWebView.loadUrl("javascript:window.java.resize($('body').outerHeight())");
假如,你的网页中某些数据需要花一段时间请求回来,那么我们也可以稍微延时一下,再获取网页的高度。
2)设置WebView高度
@JavascriptInterface
public void resize(final int height) {
// 重新设置高度
((Activity) mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
// 设置WebView高度
DisplayMetrics dm = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) mWebView.getLayoutParams();
linearParams.height = (int) (height * dm.density);
mWebView.setLayoutParams(linearParams);
}
});
}
有时,我们在使用WebView显示一个网页时,可能这个页面里面有一些比较特殊的需求,如“客服”功能,在外部浏览器点击的时候,会直接跳转到QQ页面。而使用我们自己的WebView点击“客服”的时候,没有任何反应。查看了一下这个“客服”对应的url,原来是类似这种的*”mqqwpa://im/chat?chat_type=wpa&uin=12345678&version=1&src_type=web&web_src=oicqzone.com”*,”mqqwpa”开头的这种url的话是需要QQ自己才能解析的,我们的WebView并不具备解析的功能,那我们应该如何实现跳转到QQ页面的功能呢?可以采用如下方式:
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("mqqwpa")) {
mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
});
类似的,如果是”tel”开头的url,要想实现拨打电话,我们也可以采用类似的方法,如下:
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("tel")) {
mContext.startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
});