美文网首页
Android带顶部进度条和标题的自定义WebView

Android带顶部进度条和标题的自定义WebView

作者: 小mao | 来源:发表于2017-09-23 09:38 被阅读356次

    1.简介

    开发中经常用到WebView加载网页,加载时需要显示进度条和网页标题,下面提供一个自动加载进度条和标题的WebView,进度条可自定义样式和高度,附带js与Android交互方法,可以满足大多数需求

    先上效果图

    加载中.png 加载完成.png 调用js中方法.png js调用java中方法.png

    2.ProgressWebView

    自定义ProgressWebView继承WebView

    //构造方法
    public ProgressWebView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //动态创建ProgressBar
            progressbar = new ProgressBar(context, null,
                    android.R.attr.progressBarStyleHorizontal);
            //设置ProgressBar的宽高和横纵坐标,坐标为0,0在最上方显示
            progressbar.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                    5, 0, 0));
            //将ProgressBar加入WebView
            addView(progressbar);
            setWebChromeClient(new WebChromeClient());
            setWebViewClient(new webViewClient());
        }
    
    //WebChromeClient监听进度
     public class WebChromeClient extends android.webkit.WebChromeClient {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                //当进度为100时,将进度条隐藏
                if (newProgress == 100) {
                    progressbar.setVisibility(GONE);
                } else { //不为100时,实时设置ProgressBar进度
                    if (progressbar.getVisibility() == GONE)
                        progressbar.setVisibility(VISIBLE);
                    progressbar.setProgress(newProgress);
                }
                super.onProgressChanged(view, newProgress);
            }
        }
    
    //WebViewClient监听WebView重定向和加载完成后显示标题
     class webViewClient extends WebViewClient {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
     
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //当加载完毕后,调用view.getTitle()获取网页的标题
                if(onTitleReceivedListener != null){
                    onTitleReceivedListener.onTitleReceived(view.getTitle());
                }
            }
        }
     
    //定义显示标题的接口
        public interface  OnTitleReceivedListener{
            void onTitleReceived(String title);
        }
     
    //接口set方法
        public void setOnTitleReceivedListener(OnTitleReceivedListener onTitleReceivedListener) {
            this.onTitleReceivedListener = onTitleReceivedListener;
        }
     
    //设置ProgressBar的样式,可以自定义
        public void setProgressbarDrawable(Drawable drawable){
            if(progressbar != null){
                progressbar.setProgressDrawable(drawable);
            }
        }
     
    //设置ProgressBar的高
        public void setProgressbarHeight(int height){
            LayoutParams lp = (LayoutParams) progressbar.getLayoutParams();
            lp.height = height;
            progressbar.setLayoutParams(lp);
            invalidate();
        }
    
    //最后重写onScrollChanged方法,当滑动时重新计算ProgressBar的位置
     @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            LayoutParams lp = (LayoutParams) progressbar.getLayoutParams();
            lp.x = l;
            lp.y = t;
            progressbar.setLayoutParams(lp);
            super.onScrollChanged(l, t, oldl, oldt);
        }
    

    至此,带进度条和标题的WebView完成!
    3.用法
    在xml中定义WebView

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.mao.myapp.test.WebViewTestActivity">
     
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="#FFFFFF">
         
            <ImageView
                android:id="@+id/back_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_centerVertical="true"
                android:src="@mipmap/back"/>
     
            <ImageView
                android:id="@+id/close_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/back_btn"
                android:layout_marginLeft="15dp"
                android:layout_centerVertical="true"
                android:src="@mipmap/close"/>
     
            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"/>
     
        </RelativeLayout>
     
        <com.mao.myapp.view.ProgressWebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:cacheColorHint="#00000000" />
     
    </LinearLayout>
    

    布局中包含“返回”按钮用于回退到上一步,“关闭”按钮用于关闭当前WebView,标题用于显示网页title,ProgressWebView加载网页

    在activity中可以设置ProgressBar的样式和高度

     //设置ProgressBar样式      
    mWebView.setProgressbarDrawable(getResources().getDrawable(R.drawable.web_view_progress));
    //设置ProgressBar高度
    mWebView.setProgressbarHeight(5);
    

    R.drawable.web_view_progress 为自定义的ProgressBar样式,也可以不设置,如果不设置样式默认为系统样式

    web_view_progress.xml代码

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     
        <item android:id="@android:id/background">
            <shape>
                <solid android:color="@color/colorPrimary" />
            </shape>
        </item>
     
        <item android:id="@android:id/secondaryProgress">
            <clip>
                <shape>
                    <solid android:color="@color/colorAccent"/>
                </shape>
            </clip>
        </item>
     
        <item android:id="@android:id/progress">
            <clip>
                <shape>
                    <solid android:color="@color/colorAccent"/>
                </shape>
            </clip>
        </item>
     
    </layer-list>
    

    下面是Activity完整代码

    package com.mao.myapp.test;
     
    import android.os.Build;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.DisplayMetrics;
    import android.view.View;
    import android.view.ViewGroup;
    import android.webkit.JavascriptInterface;
    import android.webkit.ValueCallback;
    import android.webkit.WebSettings;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
     
    import com.mao.myapp.R;
    import com.mao.myapp.view.ProgressWebView;
     
     
    public class WebViewTestActivity extends AppCompatActivity implements View.OnClickListener {
        private ProgressWebView mWebView;
        private ImageView backBtn, closeBtn;
        private TextView titleTv;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_web_view_test);
     
            mWebView = (ProgressWebView) findViewById(R.id.web_view);
            //设置ProgressBar样式
            mWebView.setProgressbarDrawable(getResources().getDrawable(R.drawable.web_view_progress));
            //设置ProgressBar高度
            mWebView.setProgressbarHeight(5);
            backBtn = (ImageView) findViewById(R.id.back_btn);
            backBtn.setOnClickListener(this);
            closeBtn = (ImageView) findViewById(R.id.close_btn);
            closeBtn.setOnClickListener(this);
            titleTv = (TextView) findViewById(R.id.title);
            titleTv.setOnClickListener(this);
            //加载百度
          setWebView("https://www.baidu.com/");
     
            //加载本地html,测试js与Android交互
            //setWebView("file:///android_asset/test.html");
     
            // 通过addJavascriptInterface()将Java对象映射到JS对象
            //参数1:Java对象名 参数2:Javascript对象名
            //mWebView.addJavascriptInterface(new Android2Js(), "test");
        }
     
        @Override
        protected void onResume() {
            super.onResume();
            mWebView.onResume();
        }
     
        @Override
        protected void onPause() {
            super.onPause();
            mWebView.onPause();
        }
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //将webview清空,防止内存泄漏
            if (mWebView != null) {
                mWebView.loadDataWithBaseURL(null, "", "html", "utf-8", null);
                ((ViewGroup) mWebView.getParent()).removeView(mWebView);
                mWebView.clearCache(true);
                mWebView.destroy();
                mWebView = null;
            }
        }
     
        private void setWebView(String Url) {
            WebSettings settings = mWebView.getSettings();
            settings.setJavaScriptEnabled(true);
            settings.setJavaScriptCanOpenWindowsAutomatically(true); // 支持通过JS打开新窗口
            settings.setAllowFileAccess(true);
            settings.setSupportMultipleWindows(true);
            settings.setSupportZoom(true);
            settings.setCacheMode(WebSettings.LOAD_NO_CACHE);// 不使用缓存
            settings.setDomStorageEnabled(true);
            settings.setBuiltInZoomControls(true); // 支持缩放
            settings.setLoadWithOverviewMode(true); // 初始加载时,是web页面自适应屏幕
            int screenDensity = getResources().getDisplayMetrics().densityDpi;
            WebSettings.ZoomDensity zoomDensity = WebSettings.ZoomDensity.MEDIUM;
            switch (screenDensity) {
                case DisplayMetrics.DENSITY_LOW:
                    zoomDensity = WebSettings.ZoomDensity.CLOSE;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    zoomDensity = WebSettings.ZoomDensity.MEDIUM;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    zoomDensity = WebSettings.ZoomDensity.FAR;
                    break;
            }
            settings.setDefaultZoom(zoomDensity);
            mWebView.requestFocus();
            mWebView.requestFocusFromTouch();
            //设置title
            mWebView.setOnTitleReceivedListener(new ProgressWebView.OnTitleReceivedListener() {
                @Override
                public void onTitleReceived(String title) {
                    if (title != null) {
                        titleTv.setText(title);
                    }
                }
            });
            mWebView.loadUrl(Url);
        }
     
        @Override
        public void onBackPressed() {
            //返回键处理
            if (mWebView != null && mWebView.canGoBack()) {
                mWebView.goBack();
            } else {
                finish();
            }
        }
     
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.back_btn:
                    if (mWebView != null && mWebView.canGoBack()) {
                        mWebView.goBack();
                    } else {
                        finish();
                    }
                    break;
                case R.id.close_btn:
                    finish();
                    break;
                case R.id.title:
                    //调用js中方法
                    callJs();
                    break;
            }
        }
     
        //android调用js方法:第一种通过loadUrl 第二种通过evaluateJavascript(此方法只可用在4.4及以上版本)
        public void callJs() {
            // 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                //第一种方法
                mWebView.loadUrl("javascript:callJS()");
            } else {
                //第二种方法
                mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        //value js 的返回值
                        Toast.makeText(WebViewTestActivity.this,value,Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
     
     
        class Android2Js extends Object{
            // 定义JS需要调用的方法,被JS调用的方法必须加入@JavascriptInterface注解
            @JavascriptInterface
            public void callAndroid(String msg) {
                Toast.makeText(WebViewTestActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    用起来很简单,有返回处理、关闭处理、title设置、进度条自动加载,此外,activity中还提供了与js交互的方法供参考。
    js交互

     //加载百度
    // setWebView("https://www.baidu.com/");
     
     //加载本地html,测试js与Android交互
     setWebView("file:///android_asset/test.html");
     
     // 通过addJavascriptInterface()将Java对象映射到JS对象
     //参数1:Java对象名 参数2:Javascript对象名
    mWebView.addJavascriptInterface(new Android2Js(), "test");
    

    test.html为本地html文件,用于测试js交互,放在assets文件夹下。
    test.html代码

    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="utf-8">
        <title>test_html</title>
     
        <script>
            // Android需要调用的方法
               function callJS(){
                  alert("Android调用了JS的callJS方法");
               }
     
            function callAndroid(){
                // 由于对象映射,所以调用test对象等于调用Android映射的对象
                test.callAndroid("js调用了android中的hello方法");
             }
        </script>
     
    </head>
    <body>
    <h1>hello world!!!</h1>
     
    <button type="button" id="button1" onclick="callAndroid()">click to call android func</button>
    </body>
     
    </html>
    

    如果想在activity中调用js中的方法,有两种方法:

    //android调用js方法:第一种通过loadUrl 第二种通过evaluateJavascript(此方法只可用在4.4及以上版本)
        public void callJs() {
            // 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                //第一种方法
                mWebView.loadUrl("javascript:callJS()");
            } else {
                //第二种方法
                mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        //value js 的返回值
                        Toast.makeText(WebViewTestActivity.this,value,Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
    

    我这里是点击title时调用的此方法,然后调用js种的callJS的方法。

    如果想在js种调用Android的方法,需要新建一个类继承object,并在类中声明被js调用的方法,方法必须加上 @JavascriptInterface的注解
    如下

    class Android2Js extends Object{
            // 定义JS需要调用的方法,被JS调用的方法必须加入@JavascriptInterface注解
            @JavascriptInterface
            public void callAndroid(String msg) {
                Toast.makeText(WebViewTestActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        }
    

    在加载WebView时将该类的对象和js调用此方法的对象注册

     // 通过addJavascriptInterface()将Java对象映射到JS对象
     //参数1:Java对象名 参数2:Javascript对象名
     //mWebView.addJavascriptInterface(new Android2Js(), "test");
    

    这样在js中就可用 test.callAndroid(""); 调用Android2Js中的方法
    此外,js中调用java代码还可以用其他方法,如监听js的alert、promt,或者为WebView添加webViewClient的监听,在shouldOverrideUrlLoading回调中拦截Url, 根据Url规则执行java代码。

    以上这些可以满足开发中大多数需求,如果用到WebView直接拿过来用即可。

    相关文章

      网友评论

          本文标题:Android带顶部进度条和标题的自定义WebView

          本文链接:https://www.haomeiwen.com/subject/huotextx.html