android WebView常见功能处理(视频全屏,错误页等)

虽然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





发布了13 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/lanqi_x/article/details/70157453
今日推荐