雖然android的webview現在可以直接接入騰訊的X5或者UC WebView SDK,都號稱更穩定更快和適配更方便。但實際開發中不一定所有的產品都會接入它們,像x5在視頻全屏時會有QQ瀏覽器的下載鏈接(我沒查文檔,不知道可不可以去掉的),一不小心點到就去下載了,且在我使用的時候就適配而言並沒有比原生的好多少。不論怎麼說多會點東西總不會虧。本篇文章講的是1、修改WebView原本的錯誤頁處理2、頁面跳轉的處理3、頁面加載進度條的處理4、視頻全屏處理。主要實現方式就是處理WebViewClient和WebChromeClient。不喜歡看說明的可以直接拉到底部有demo下載地址。本文地址:http://blog.csdn.net/lanqi_x/article/details/70157453
一、修改WebView原本的錯誤頁處理和頁面跳轉的處理,這兩個功能是在WebViewClient中處理。
1、頁面跳轉的處理基本上所有的android開發者都知道怎麼處理,就不多說了,直接貼代碼
/**
* 點擊網頁中按鈕時,讓其還在原頁面打開
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http")) {
if (loadNewUrlListener != null) {
if (!loadNewUrlListener.loadNewUrl(view, url)) {
view.loadUrl(url);
}
} else {
view.loadUrl(url);
}
} else {
// 非http和https請求丟給系統處理,比如撥打電話等
try {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
view.getContext().startActivity(intent);
} catch (Exception e) {
// 沒有安裝對應的應用會拋異常
e.printStackTrace();
}
}
return true;
}
2、修改WebView原本的錯誤頁,這個我的處理思路是當頁面加載錯誤時,會調用onReceivedError方法,在這個時候我把WebView給隱藏了,然後拿到WebView的父控件,在對於WebView的位置上加入我自己定義的錯誤頁佈局。當重新加載沒有錯誤時就把這個錯誤頁移除掉,再將WebView顯示處理。來吧,貼一小段代碼吧!
/**
* 頁面加載結束
*
* @param view
* @param url
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
hideErrorPage(view);
if (pagefinish != null) {
pagefinish.pageFinished(view, url);
}
pageIsFinished = true;
}
/**
* 加載錯誤
*
* @param view
* @param request
* @param error
*/
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
showErrorPage(view);
}
/**
* 加載錯誤
*
* @param view
* @param errorCode
* @param description
* @param failingUrl
*/
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
showErrorPage(view);
}
private View mErrorView;
private boolean loadError;
/**
* 顯示錯誤頁
*
* @param webView
*/
protected void showErrorPage(final WebView webView) {
if (customizeErrorPage) {
ViewGroup viewParent = (ViewGroup) webView.getParent();
if (mErrorView == null) {
mErrorView = View.inflate(webView.getContext(), R.layout.view_webview_error, null);
mErrorView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
webView.reload();
}
});
}
int i = viewParent.indexOfChild(webView);
if (viewParent.indexOfChild(mErrorView) == -1) {
ViewGroup.LayoutParams lp = webView.getLayoutParams();
webView.setVisibility(View.GONE);
viewParent.addView(mErrorView, i, lp);
}
loadError = true;
}
}
/****
* 隱藏錯誤頁
*/
protected void hideErrorPage(final WebView webView) {
if (customizeErrorPage && mErrorView != null) {
if (!loadError) {
ViewGroup viewParent = (ViewGroup) mErrorView.getParent();
if (viewParent != null) {
int i = viewParent.indexOfChild(mErrorView);
if (i != -1) {
viewParent.removeView(mErrorView);
}
}
loadError = false;
mErrorView = null;
// 防止較卡的手機閃現WebView的錯誤頁
webView.postDelayed(new Runnable() {
@Override
public void run() {
webView.setVisibility(View.VISIBLE);
}
}, 200);
}
}
}
二、頁面加載進度條的處理和視頻全屏處理,這兩個我是放在WebChromeClient中處理的。
1、先說簡單的加載進度條的處理。WebChromeClient有個onProgressChanged方法,這裏會傳進頁面加載的進度,在這裏我們就可以處理進度條了。
/**頁面加載進度處理
* @param view
* @param newProgress
*/
@Override
public void onProgressChanged(WebView view, int newProgress) {
handle.removeMessages(1);
if (progressBar != null) {
if (progressBar.getProgress() == 0) {
progressBar.setVisibility(View.VISIBLE);
}
for (int i = this.progressBar.getProgress(); i <= newProgress; i++) {
Message message = new Message();
message.what = 1;
message.obj = i;
handle.sendMessageDelayed(message, i * 5);
}
}
super.onProgressChanged(view, newProgress);
}
private Handler handle = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
progressBar.setProgress((int) msg.obj);
if ((int) msg.obj == 100) {
progressBar.setVisibility(View.GONE);
progressBar.setProgress(0);
}
}
};
2、視頻全屏處理,這裏用到了WebChromeClient的onShowCustomView和onHideCustomView方法,分別是用戶點擊了全屏和關閉全屏時調用。我的處理方式是這樣的,onShowCustomView會傳個參數View進來,這個view就是視頻播放的view,我們見他放進我們要顯示的ViewGrop就可以了,而在onHideCustomView中將其移除就行。
我採取外部傳參數的方式,即使用這個WebChromeClient時傳個FrameLayout進來,在全屏的時候FrameLayout.add(view);代碼如下:
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (videoView == null) {
super.onShowCustomView(view, callback);
} else {
if (view instanceof FrameLayout) {
FrameLayout frameLayout = (FrameLayout) view;
View focusedChild = frameLayout.getFocusedChild();
// 更改狀態
this.isVideoFullscreen = true;
this.videoViewContainer = frameLayout;
this.videoViewCallback = callback;
// 隱藏佈局
noVideoView.setVisibility(View.INVISIBLE);
// 將網頁視頻的View ,加入顯示的地方
videoView.addView(videoViewContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
videoView.setVisibility(View.VISIBLE);
// 添加視頻播放事件
if (focusedChild instanceof android.widget.VideoView) {
// android.widget.VideoView (typically API level <11)
android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;
// Handle all the required events
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
videoView.setOnErrorListener(this);
}
// Notify full-screen change
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(true);
}
}else {
super.onShowCustomView(view, callback);
}
}
}
@Override
@SuppressWarnings("deprecation")
public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) // Available in API level 14+, deprecated in API level 18+
{
onShowCustomView(view, callback);
}
@Override
public void onHideCustomView() {
if (videoView == null) {
super.onHideCustomView();
} else {
if (isVideoFullscreen) {
videoView.setVisibility(View.INVISIBLE);
videoView.removeView(videoViewContainer);
noVideoView.setVisibility(View.VISIBLE);
// Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)
if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium.")) {
videoViewCallback.onCustomViewHidden();
}
isVideoFullscreen = false;
videoViewContainer = null;
videoViewCallback = null;
if (toggledFullscreenCallback != null) {
toggledFullscreenCallback.toggledFullscreen(false);
}
}else {
super.onHideCustomView();
}
}
}
其實如果所有的地方顯示的界面比較統一的話可以採取約定大於配置的思路,就是約定好如要使用這個全屏功能,那個這個界面的根佈局必須是FrameLayout,那麼videoView就可以寫死在WebChromeClient內,通過獲取webView所在佈局的根佈局,再將videoView給add進去就行了, 簡單代碼如下,但未經測試,僅供參考:
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
ViewGroup parentView= (ViewGroup) webView.getParent();
while (parentView.getParent() != null){
parentView = (ViewGroup) parentView.getParent();
}
FrameLayout videoView=new FrameLayout (webView.getContext());
videoView.setBackgroundColor(0x000000);
videoView.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
parentView.addView(videoView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
下載地址https://github.com/lanqi-x/webViewPro