我们直接上代码,复制就可以用
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>