Android带加载进度条的WebView

我们直接上代码,复制就可以用

public class WebProgress extends FrameLayout {

    /**
     * 默认匀速动画最大的时长
     */
    public static final int MAX_UNIFORM_SPEED_DURATION = 8 * 1000;
    /**
     * 默认加速后减速动画最大时长
     */
    public static final int MAX_DECELERATE_SPEED_DURATION = 450;
    /**
     * 95f-100f时,透明度1f-0f时长
     */
    public static final int DO_END_ALPHA_DURATION = 630;
    /**
     * 95f - 100f动画时长
     */
    public static final int DO_END_PROGRESS_DURATION = 500;
    /**
     * 当前匀速动画最大的时长
     */
    private static int CURRENT_MAX_UNIFORM_SPEED_DURATION = MAX_UNIFORM_SPEED_DURATION;
    /**
     * 当前加速后减速动画最大时长
     */
    private static int CURRENT_MAX_DECELERATE_SPEED_DURATION = MAX_DECELERATE_SPEED_DURATION;
    /**
     * 默认的高度(dp)
     */
    public static int WEB_PROGRESS_DEFAULT_HEIGHT = 3;
    /**
     * 进度条颜色默认
     */
    public static String WEB_PROGRESS_COLOR = "#2483D9";
    /**
     * 进度条颜色
     */
    private int mColor;
    /**
     * 进度条的画笔
     */
    private Paint mPaint;
    /**
     * 进度条动画
     */
    private Animator mAnimator;
    /**
     * 控件的宽度
     */
    private int mTargetWidth = 0;
    /**
     * 控件的高度
     */
    private int mTargetHeight;
    /**
     * 标志当前进度条的状态
     */
    private int TAG = 0;
    /**
     * 第一次过来进度show,后面就是setProgress
     */
    private boolean isShow = false;
    /**
     * 用来记录不能继续开始
     */
    public static final int UN_START = 0;
    /**
     * 用来记录已经开始,当开始执行加载动画后就切换到该状态
     */
    public static final int STARTED = 1;
    /**
     * 用来记录已经结束
     */
    public static final int FINISH = 2;
    /**
     * 百分比进度值
     */
    private float mCurrentProgress = 0F;

    public WebProgress(Context context) {
        this(context, null);
    }

    public WebProgress(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WebProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    /**
     * 创建的时候
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    /**
     * 销毁的时候,注意记得清楚动画资源
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        /**
         * animator cause leak , if not cancel;
         */
        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
            mAnimator = null;
        }
    }


    /**
     * 初始化操作
     * @param context                           上下文
     * @param attrs                             attrs属性
     * @param defStyleAttr                      defStyleAttr
     */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        //创建画笔,设置属性
        mPaint = new Paint();
        mColor = Color.parseColor(WEB_PROGRESS_COLOR);
        mPaint.setAntiAlias(true);
        //设置颜色
        mPaint.setColor(mColor);
        mPaint.setDither(true);
        mPaint.setStrokeCap(Paint.Cap.SQUARE);

        mTargetWidth = context.getResources().getDisplayMetrics().widthPixels;
        mTargetHeight = dip2px(WEB_PROGRESS_DEFAULT_HEIGHT);
    }

    /**
     * 设置单色进度条
     */
    public void setColor(int color) {
        this.mColor = color;
        mPaint.setColor(color);
    }

    /**
     * 设置单色进度条
     * @param color                     颜色
     */
    public void setColor(String color) {
        this.setColor(Color.parseColor(color));
    }

    /**
     * 设置渐变色进度条
     *
     * @param startColor                        开始颜色
     * @param endColor                          结束颜色
     */
    public void setColor(int startColor, int endColor) {
        try {
            LinearGradient linearGradient = new LinearGradient(0, 0, mTargetWidth,
                    mTargetHeight, startColor, endColor, Shader.TileMode.CLAMP);
            mPaint.setShader(linearGradient);
        } catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 设置渐变色进度条
     *
     * @param startColor                        开始颜色
     * @param endColor                          结束颜色
     */
    public void setColor(String startColor, String endColor) {
        this.setColor(Color.parseColor(startColor), Color.parseColor(endColor));
    }

    /**
     * 测量方法
     * @param widthMeasureSpec                  widthMeasureSpec
     * @param heightMeasureSpec                 heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int w = MeasureSpec.getSize(widthMeasureSpec);
        int h = MeasureSpec.getSize(heightMeasureSpec);

        if (wMode == MeasureSpec.AT_MOST) {
            DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
            w = w <= displayMetrics.widthPixels ? w : displayMetrics.widthPixels;
        }
        if (hMode == MeasureSpec.AT_MOST) {
            h = mTargetHeight;
        }
        this.setMeasuredDimension(w, h);
    }

    @Override
    protected void onDraw(Canvas canvas) {

    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.drawRect(0, 0,
                mCurrentProgress / 100 * Float.valueOf(this.getWidth()), this.getHeight(), mPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mTargetWidth = getMeasuredWidth();
        int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
        if (mTargetWidth >= screenWidth) {
            CURRENT_MAX_DECELERATE_SPEED_DURATION = MAX_DECELERATE_SPEED_DURATION;
            CURRENT_MAX_UNIFORM_SPEED_DURATION = MAX_UNIFORM_SPEED_DURATION;
        } else {
            //取比值
            float rate = (float) (this.mTargetWidth / (screenWidth*1.0));
            CURRENT_MAX_UNIFORM_SPEED_DURATION = (int) (MAX_UNIFORM_SPEED_DURATION * rate);
            CURRENT_MAX_DECELERATE_SPEED_DURATION = (int) (MAX_DECELERATE_SPEED_DURATION * rate);
        }
    }

    private void setFinish() {
        isShow = false;
        TAG = FINISH;
    }

    /**
     * 开始动画
     */
    private void startAnim(boolean isFinished) {
        float v = isFinished ? 100 : 95;
        //先清除动画资源
        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
        }
        mCurrentProgress = ((int)mCurrentProgress) == 0f ? 0.00000001f : mCurrentProgress;

        if (!isFinished) {
            //如果还没有完成
            ValueAnimator mAnimator = ValueAnimator.ofFloat(mCurrentProgress, v);
            float residue = 1f - mCurrentProgress / 100 - 0.05f;
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.setDuration((long) (residue * CURRENT_MAX_UNIFORM_SPEED_DURATION));
            mAnimator.addUpdateListener(mAnimatorUpdateListener);
            mAnimator.start();
            this.mAnimator = mAnimator;
        } else {
            //如果还没有完成
            ValueAnimator segment95Animator = null;
            if (mCurrentProgress < 95f) {
                segment95Animator = ValueAnimator.ofFloat(mCurrentProgress, 95);
                float residue = 1f - mCurrentProgress / 100f - 0.05f;
                segment95Animator.setInterpolator(new LinearInterpolator());
                segment95Animator.setDuration((long) (residue * CURRENT_MAX_DECELERATE_SPEED_DURATION));
                segment95Animator.setInterpolator(new DecelerateInterpolator());
                segment95Animator.addUpdateListener(mAnimatorUpdateListener);
            }

            ObjectAnimator mObjectAnimator = ObjectAnimator.ofFloat(
                    this, "alpha", 1f, 0f);
            mObjectAnimator.setDuration(DO_END_ALPHA_DURATION);
            ValueAnimator mValueAnimatorEnd = ValueAnimator.ofFloat(95f, 100f);
            mValueAnimatorEnd.setDuration(DO_END_PROGRESS_DURATION);
            mValueAnimatorEnd.addUpdateListener(mAnimatorUpdateListener);

            AnimatorSet mAnimatorSet = new AnimatorSet();
            mAnimatorSet.playTogether(mObjectAnimator, mValueAnimatorEnd);

            if (segment95Animator != null) {
                AnimatorSet mAnimatorSet1 = new AnimatorSet();
                mAnimatorSet1.play(mAnimatorSet).after(segment95Animator);
                mAnimatorSet = mAnimatorSet1;
            }
            mAnimatorSet.addListener(mAnimatorListener);
            mAnimatorSet.start();
            mAnimator = mAnimatorSet;
        }

        TAG = STARTED;
    }

    /**
     * 创建属性动画监听进度变化的对象
     */
    private ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener =
            new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float t = (float) animation.getAnimatedValue();
                    //更改进度
                    WebProgress.this.mCurrentProgress = t;
                    //调用invalidate方法刷新UI
                    WebProgress.this.invalidate();
                }
            };

    /**
     * 创建属性动画监听的对象
     */
    private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            doEnd();
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            super.onAnimationCancel(animation);
        }

        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
        }
    };

    private void doEnd() {
        if (TAG == FINISH && ((int)mCurrentProgress) == 100f) {
            setVisibility(GONE);
            mCurrentProgress = 0f;
            this.setAlpha(1f);
        }
        TAG = UN_START;
    }

    public void reset() {
        mCurrentProgress = 0;
        if (mAnimator != null && mAnimator.isStarted()) {
            mAnimator.cancel();
        }
    }

    /**
     * 设置进度
     * @param progress                          进度值
     */
    public void setProgress(int progress) {
        // fix 同时返回两个 100,产生两次进度条的问题;
        if (TAG == UN_START && progress == 100f) {
            setVisibility(View.GONE);
            return;
        }
        if (getVisibility() == View.GONE) {
            setVisibility(View.VISIBLE);
        }
        if (progress < 95f) {
            return;
        }
        if (TAG != FINISH) {
            startAnim(true);
        }
    }

    public LayoutParams offerLayoutParams() {
        return new LayoutParams(mTargetWidth, mTargetHeight);
    }

    private int dip2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 显示进度条
     */
    public void show() {
        isShow = true;
        setVisibility(View.VISIBLE);
        mCurrentProgress = 0f;
        startAnim(false);
    }

    /**
     * 进度完成后消失
     */
    public void hide() {
        setWebProgress(100);
    }

    /**
     * 为单独处理WebView进度条
     */
    public void setWebProgress(int newProgress) {
        if (newProgress >= 0 && newProgress < 95) {
            if (!isShow) {
                show();
            } else {
                setProgress(newProgress);
            }
        } else {
            setProgress(newProgress);
            setFinish();
        }
    }
}

public class MainActivity extends AppCompatActivity {
    private WebView webView;
    private WebProgress progress;
    private TextView tvTitle;
    private TextView tvRefresh;
    private RotateAnimation rotate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = findViewById(R.id.web_view);
        progress = findViewById(R.id.progress);
        tvTitle = findViewById(R.id.tv_title);
        tvRefresh = findViewById(R.id.tv_refresh);

        progress.show();
        progress.setColor(this.getResources().getColor(R.color.colorAccent),this.getResources().getColor(R.color.colorPrimaryDark));
        webView.setWebViewClient(new MyWebViewClient());
        webView.setWebChromeClient(new MyWebChromeClient());
        final String url = "http://www.baidu.com";
        webView.loadUrl(url);
        tvRefresh.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                webView.loadUrl(url);
            }
        });
    }

    private class MyWebViewClient extends WebViewClient {

//        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
//        @Override
//        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
//            String s = request.getUrl().toString();
//            X5LogUtils.i("-------shouldOverrideUrlLoading----->21--"+s);
//            //view.loadUrl(s);
//            //return true;
//            return super.shouldOverrideUrlLoading(view, request);
//        }


        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            //判断重定向的方式一
            LogUtil.i("-----shouldOverrideUrlLoading---------",url);
            WebView.HitTestResult hitTestResult = view.getHitTestResult();
            if(hitTestResult == null) {
                return false;
            }
            if(hitTestResult.getType() == WebView.HitTestResult.UNKNOWN_TYPE) {
                //X5LogUtils.i("-------重定向-------");
                return false;
            }
            view.loadUrl(url);
            //X5LogUtils.i("-----shouldOverrideUrlLoading-----2----"+url);
//            running++;
            return true;

            //return super.shouldOverrideUrlLoading(view, url);
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            LogUtil.i("-------onPageStarted-------",url);
//            running = Math.max(running, 1);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            LogUtil.i("-------onPageFinished-------",url);
//            if (--running==0) {
//                //做操作,隐藏加载进度条或者加载loading
//                X5LogUtils.i("-------onPageFinished-----结束--");
//            }
        }
    }
    private class MyWebChromeClient extends WebChromeClient {
        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
            LogUtil.i("-------onReceivedTitle-------",title);
            //bar.setTitle(title));
            getWebTitle(view);
//            if (--running==0) {
//                bar.setTitle(title);
//            }
        }

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            progress.setWebProgress(newProgress);
        }
    }

    private void getWebTitle(WebView view){
        WebBackForwardList forwardList = view.copyBackForwardList();
        WebHistoryItem item = forwardList.getCurrentItem();
        if (item != null) {
            tvTitle.setText(item.getTitle());
            // X5LogUtils.i("-------onReceivedTitle----getWebTitle---"+item.getTitle());
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (webView.canGoBack()) {
                webView.goBack();
                return true;
                //退出网页
            } else {
                handleFinish();
            }
        }
        return false;
    }

    public void handleFinish() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            finishAfterTransition();
        } else {
            finish();
        }
    }


    @Override
    protected void onDestroy() {
        try {
            if (webView != null) {
                webView.destroy();
                webView = null;
            }
            if (rotate!=null){
                rotate.cancel();
            }
        } catch (Exception e) {
            Log.e("X5WebViewActivity", e.getMessage());
        }
        super.onDestroy();
    }
}
public class LogUtil {
    //日志输出级别NONE
    public static final int LEVEL_NONE = 0;
    //日志输出级别E
    public static final int LEVEL_ERROR = 1;
    //日志输出级别W
    public static final int LEVEL_WARN = 2;
    //日志输出级别I
    public static final int LEVEL_INFO = 3;
    //日志输出级别D
    public static final int LEVEL_DEBUG = 4;
    //日志输出级别V
    public static final int LEVEL_VERBOSE = 5;

    //日志输出时的Tag
    private static String mTag = "LogUtil";
    //当前日志输出级别(是否允许输出log)
    private static int mCurrentLevel = LEVEL_VERBOSE;

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void v(String tag, String msg) {
        if (mCurrentLevel >= LEVEL_VERBOSE) {
            Log.v(tag, msg);
        }
    }

    /**
     * 以级别为 d 的形式输出LOG
     */
    public static void d(String tag, String msg) {
        if (mCurrentLevel >= LEVEL_DEBUG) {
            Log.d(tag, msg);
        }
    }

    /**
     * 以级别为 i 的形式输出LOG
     */
    public static void i(String tag, String msg) {
        if (mCurrentLevel >= LEVEL_INFO) {
            Log.i(tag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出LOG
     */
    public static void w(String tag, String msg) {
        if (mCurrentLevel >= LEVEL_WARN) {
            Log.w(tag, msg);
        }
    }

    /**
     * 以级别为 w 的形式输出Throwable
     */
    public static void w(Throwable tr) {
        if (mCurrentLevel >= LEVEL_WARN) {
            Log.w(mTag, "", tr);
        }
    }

    /**
     * 以级别为 w 的形式输出LOG信息和Throwable
     */
    public static void w(String msg, Throwable tr) {
        if (mCurrentLevel >= LEVEL_WARN && null != msg) {
            Log.w(mTag, msg, tr);
        }
    }

    /**
     * 以级别为 e 的形式输出LOG
     */
    public static void e(String tag, String msg) {
        if (mCurrentLevel >= LEVEL_ERROR) {
            Log.e(tag, msg);
        }
    }

    /**
     * 以级别为 e 的形式输出Throwable
     */
    public static void e(Throwable tr) {
        if (mCurrentLevel >= LEVEL_ERROR) {
            Log.e(mTag, "", tr);
        }
    }

    /**
     * 以级别为 e 的形式输出LOG信息和Throwable
     */
    public static void e(String msg, Throwable tr) {
        if (mCurrentLevel >= LEVEL_ERROR && null != msg) {
            Log.e(mTag, msg, tr);
        }
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/colorPrimary">
        <TextView
            android:id="@+id/tv_title"
            android:text="标题"
            android:textSize="18sp"
            android:textColor="@color/colorAccent"
            android:gravity="center"
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"/>

        <TextView
            android:id="@+id/tv_refresh"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="15dp"
            android:textColor="@color/colorAccent"
            android:text="刷新"/>
    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <!--仿微信横向进度条-->
        <com.szbb.webview.WebProgress
            android:id="@+id/progress"
            android:layout_width="match_parent"
            android:layout_height="3dp"/>
    </FrameLayout>

</LinearLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值