Android带加载进度条的WebView

简介: Android带加载进度条的WebView

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

publicclassWebProgressextendsFrameLayout {
/*** 默认匀速动画最大的时长*/publicstaticfinalintMAX_UNIFORM_SPEED_DURATION=8*1000;
/*** 默认加速后减速动画最大时长*/publicstaticfinalintMAX_DECELERATE_SPEED_DURATION=450;
/*** 95f-100f时,透明度1f-0f时长*/publicstaticfinalintDO_END_ALPHA_DURATION=630;
/*** 95f - 100f动画时长*/publicstaticfinalintDO_END_PROGRESS_DURATION=500;
/*** 当前匀速动画最大的时长*/privatestaticintCURRENT_MAX_UNIFORM_SPEED_DURATION=MAX_UNIFORM_SPEED_DURATION;
/*** 当前加速后减速动画最大时长*/privatestaticintCURRENT_MAX_DECELERATE_SPEED_DURATION=MAX_DECELERATE_SPEED_DURATION;
/*** 默认的高度(dp)*/publicstaticintWEB_PROGRESS_DEFAULT_HEIGHT=3;
/*** 进度条颜色默认*/publicstaticStringWEB_PROGRESS_COLOR="#2483D9";
/*** 进度条颜色*/privateintmColor;
/*** 进度条的画笔*/privatePaintmPaint;
/*** 进度条动画*/privateAnimatormAnimator;
/*** 控件的宽度*/privateintmTargetWidth=0;
/*** 控件的高度*/privateintmTargetHeight;
/*** 标志当前进度条的状态*/privateintTAG=0;
/*** 第一次过来进度show,后面就是setProgress*/privatebooleanisShow=false;
/*** 用来记录不能继续开始*/publicstaticfinalintUN_START=0;
/*** 用来记录已经开始,当开始执行加载动画后就切换到该状态*/publicstaticfinalintSTARTED=1;
/*** 用来记录已经结束*/publicstaticfinalintFINISH=2;
/*** 百分比进度值*/privatefloatmCurrentProgress=0F;
publicWebProgress(Contextcontext) {
this(context, null);
    }
publicWebProgress(Contextcontext, @NullableAttributeSetattrs) {
this(context, attrs, 0);
    }
publicWebProgress(Contextcontext, @NullableAttributeSetattrs, intdefStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
    }
/*** 创建的时候*/@OverrideprotectedvoidonAttachedToWindow() {
super.onAttachedToWindow();
    }
/*** 销毁的时候,注意记得清楚动画资源*/@OverrideprotectedvoidonDetachedFromWindow() {
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*/privatevoidinit(Contextcontext, AttributeSetattrs, intdefStyleAttr) {
//创建画笔,设置属性mPaint=newPaint();
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);
    }
/*** 设置单色进度条*/publicvoidsetColor(intcolor) {
this.mColor=color;
mPaint.setColor(color);
    }
/*** 设置单色进度条* @param color                     颜色*/publicvoidsetColor(Stringcolor) {
this.setColor(Color.parseColor(color));
    }
/*** 设置渐变色进度条** @param startColor                        开始颜色* @param endColor                          结束颜色*/publicvoidsetColor(intstartColor, intendColor) {
try {
LinearGradientlinearGradient=newLinearGradient(0, 0, mTargetWidth,
mTargetHeight, startColor, endColor, Shader.TileMode.CLAMP);
mPaint.setShader(linearGradient);
        } catch (Exceptione){
e.printStackTrace();
        }
    }
/*** 设置渐变色进度条** @param startColor                        开始颜色* @param endColor                          结束颜色*/publicvoidsetColor(StringstartColor, StringendColor) {
this.setColor(Color.parseColor(startColor), Color.parseColor(endColor));
    }
/*** 测量方法* @param widthMeasureSpec                  widthMeasureSpec* @param heightMeasureSpec                 heightMeasureSpec*/@OverrideprotectedvoidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
intwMode=MeasureSpec.getMode(widthMeasureSpec);
inthMode=MeasureSpec.getMode(heightMeasureSpec);
intw=MeasureSpec.getSize(widthMeasureSpec);
inth=MeasureSpec.getSize(heightMeasureSpec);
if (wMode==MeasureSpec.AT_MOST) {
DisplayMetricsdisplayMetrics=getContext().getResources().getDisplayMetrics();
w=w<=displayMetrics.widthPixels?w : displayMetrics.widthPixels;
        }
if (hMode==MeasureSpec.AT_MOST) {
h=mTargetHeight;
        }
this.setMeasuredDimension(w, h);
    }
@OverrideprotectedvoidonDraw(Canvascanvas) {
    }
@OverrideprotectedvoiddispatchDraw(Canvascanvas) {
canvas.drawRect(0, 0,
mCurrentProgress/100*Float.valueOf(this.getWidth()), this.getHeight(), mPaint);
    }
@OverrideprotectedvoidonSizeChanged(intw, inth, intoldw, intoldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.mTargetWidth=getMeasuredWidth();
intscreenWidth=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 {
//取比值floatrate= (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);
        }
    }
privatevoidsetFinish() {
isShow=false;
TAG=FINISH;
    }
/*** 开始动画*/privatevoidstartAnim(booleanisFinished) {
floatv=isFinished?100 : 95;
//先清除动画资源if (mAnimator!=null&&mAnimator.isStarted()) {
mAnimator.cancel();
        }
mCurrentProgress= ((int)mCurrentProgress) ==0f?0.00000001f : mCurrentProgress;
if (!isFinished) {
//如果还没有完成ValueAnimatormAnimator=ValueAnimator.ofFloat(mCurrentProgress, v);
floatresidue=1f-mCurrentProgress/100-0.05f;
mAnimator.setInterpolator(newLinearInterpolator());
mAnimator.setDuration((long) (residue*CURRENT_MAX_UNIFORM_SPEED_DURATION));
mAnimator.addUpdateListener(mAnimatorUpdateListener);
mAnimator.start();
this.mAnimator=mAnimator;
        } else {
//如果还没有完成ValueAnimatorsegment95Animator=null;
if (mCurrentProgress<95f) {
segment95Animator=ValueAnimator.ofFloat(mCurrentProgress, 95);
floatresidue=1f-mCurrentProgress/100f-0.05f;
segment95Animator.setInterpolator(newLinearInterpolator());
segment95Animator.setDuration((long) (residue*CURRENT_MAX_DECELERATE_SPEED_DURATION));
segment95Animator.setInterpolator(newDecelerateInterpolator());
segment95Animator.addUpdateListener(mAnimatorUpdateListener);
            }
ObjectAnimatormObjectAnimator=ObjectAnimator.ofFloat(
this, "alpha", 1f, 0f);
mObjectAnimator.setDuration(DO_END_ALPHA_DURATION);
ValueAnimatormValueAnimatorEnd=ValueAnimator.ofFloat(95f, 100f);
mValueAnimatorEnd.setDuration(DO_END_PROGRESS_DURATION);
mValueAnimatorEnd.addUpdateListener(mAnimatorUpdateListener);
AnimatorSetmAnimatorSet=newAnimatorSet();
mAnimatorSet.playTogether(mObjectAnimator, mValueAnimatorEnd);
if (segment95Animator!=null) {
AnimatorSetmAnimatorSet1=newAnimatorSet();
mAnimatorSet1.play(mAnimatorSet).after(segment95Animator);
mAnimatorSet=mAnimatorSet1;
            }
mAnimatorSet.addListener(mAnimatorListener);
mAnimatorSet.start();
mAnimator=mAnimatorSet;
        }
TAG=STARTED;
    }
/*** 创建属性动画监听进度变化的对象*/privateValueAnimator.AnimatorUpdateListenermAnimatorUpdateListener=newValueAnimator.AnimatorUpdateListener() {
@OverridepublicvoidonAnimationUpdate(ValueAnimatoranimation) {
floatt= (float) animation.getAnimatedValue();
//更改进度WebProgress.this.mCurrentProgress=t;
//调用invalidate方法刷新UIWebProgress.this.invalidate();
                }
            };
/*** 创建属性动画监听的对象*/privateAnimatorListenerAdaptermAnimatorListener=newAnimatorListenerAdapter() {
@OverridepublicvoidonAnimationEnd(Animatoranimation) {
doEnd();
        }
@OverridepublicvoidonAnimationCancel(Animatoranimation) {
super.onAnimationCancel(animation);
        }
@OverridepublicvoidonAnimationStart(Animatoranimation) {
super.onAnimationStart(animation);
        }
    };
privatevoiddoEnd() {
if (TAG==FINISH&& ((int)mCurrentProgress) ==100f) {
setVisibility(GONE);
mCurrentProgress=0f;
this.setAlpha(1f);
        }
TAG=UN_START;
    }
publicvoidreset() {
mCurrentProgress=0;
if (mAnimator!=null&&mAnimator.isStarted()) {
mAnimator.cancel();
        }
    }
/*** 设置进度* @param progress                          进度值*/publicvoidsetProgress(intprogress) {
// 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);
        }
    }
publicLayoutParamsofferLayoutParams() {
returnnewLayoutParams(mTargetWidth, mTargetHeight);
    }
privateintdip2px(floatdpValue) {
finalfloatscale=getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue*scale+0.5f);
    }
/*** 显示进度条*/publicvoidshow() {
isShow=true;
setVisibility(View.VISIBLE);
mCurrentProgress=0f;
startAnim(false);
    }
/*** 进度完成后消失*/publicvoidhide() {
setWebProgress(100);
    }
/*** 为单独处理WebView进度条*/publicvoidsetWebProgress(intnewProgress) {
if (newProgress>=0&&newProgress<95) {
if (!isShow) {
show();
            } else {
setProgress(newProgress);
            }
        } else {
setProgress(newProgress);
setFinish();
        }
    }
}
publicclassMainActivityextendsAppCompatActivity {
privateWebViewwebView;
privateWebProgressprogress;
privateTextViewtvTitle;
privateTextViewtvRefresh;
privateRotateAnimationrotate;
@OverrideprotectedvoidonCreate(BundlesavedInstanceState) {
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(newMyWebViewClient());
webView.setWebChromeClient(newMyWebChromeClient());
finalStringurl="http://www.baidu.com";
webView.loadUrl(url);
tvRefresh.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewview) {
webView.loadUrl(url);
            }
        });
    }
privateclassMyWebViewClientextendsWebViewClient {
//        @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);//        }@OverridepublicbooleanshouldOverrideUrlLoading(WebViewview, Stringurl) {
//判断重定向的方式一LogUtil.i("-----shouldOverrideUrlLoading---------",url);
WebView.HitTestResulthitTestResult=view.getHitTestResult();
if(hitTestResult==null) {
returnfalse;
            }
if(hitTestResult.getType() ==WebView.HitTestResult.UNKNOWN_TYPE) {
//X5LogUtils.i("-------重定向-------");returnfalse;
            }
view.loadUrl(url);
//X5LogUtils.i("-----shouldOverrideUrlLoading-----2----"+url);//            running++;returntrue;
//return super.shouldOverrideUrlLoading(view, url);        }
@OverridepublicvoidonPageStarted(WebViewview, Stringurl, Bitmapfavicon) {
super.onPageStarted(view, url, favicon);
LogUtil.i("-------onPageStarted-------",url);
//            running = Math.max(running, 1);        }
@OverridepublicvoidonPageFinished(WebViewview, Stringurl) {
super.onPageFinished(view, url);
LogUtil.i("-------onPageFinished-------",url);
//            if (--running==0) {//                //做操作,隐藏加载进度条或者加载loading//                X5LogUtils.i("-------onPageFinished-----结束--");//            }        }
    }
privateclassMyWebChromeClientextendsWebChromeClient {
@OverridepublicvoidonReceivedTitle(WebViewview, Stringtitle) {
super.onReceivedTitle(view, title);
LogUtil.i("-------onReceivedTitle-------",title);
//bar.setTitle(title));getWebTitle(view);
//            if (--running==0) {//                bar.setTitle(title);//            }        }
@OverridepublicvoidonProgressChanged(WebViewview, intnewProgress) {
super.onProgressChanged(view, newProgress);
progress.setWebProgress(newProgress);
        }
    }
privatevoidgetWebTitle(WebViewview){
WebBackForwardListforwardList=view.copyBackForwardList();
WebHistoryItemitem=forwardList.getCurrentItem();
if (item!=null) {
tvTitle.setText(item.getTitle());
// X5LogUtils.i("-------onReceivedTitle----getWebTitle---"+item.getTitle());        }
    }
@OverridepublicbooleanonKeyDown(intkeyCode, KeyEventevent) {
if (keyCode==KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack();
returntrue;
//退出网页            } else {
handleFinish();
            }
        }
returnfalse;
    }
publicvoidhandleFinish() {
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) {
finishAfterTransition();
        } else {
finish();
        }
    }
@OverrideprotectedvoidonDestroy() {
try {
if (webView!=null) {
webView.destroy();
webView=null;
            }
if (rotate!=null){
rotate.cancel();
            }
        } catch (Exceptione) {
Log.e("X5WebViewActivity", e.getMessage());
        }
super.onDestroy();
    }
}
相关文章
|
5月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
147 2
|
2月前
|
程序员 开发工具 Android开发
Android|WebView 禁止长按,限制非白名单域名的跳转层级
如何限制 WebView 仅域名白名单网址能随意跳转,并禁用长按选择文字。
34 2
|
2月前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
4月前
|
Android开发
【Azure 环境】移动应用 SSO 登录AAD, MSAL的配置为Webview模式时登录页面无法加载
【Azure 环境】移动应用 SSO 登录AAD, MSAL的配置为Webview模式时登录页面无法加载
|
4月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
47 0
|
4月前
|
Java Android开发 Kotlin
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
38 0
|
6月前
|
Android开发 UED Kotlin
kotlin webview 加载网页失败后如何再次重试
在Kotlin中,当使用WebView加载网页失败时,可通过设置WebViewClient并覆盖`onReceivedError`方法来捕获失败事件。在该回调中,可以显示错误信息或尝试使用`reload()`重试加载。以下是一个简要示例展示如何处理加载失败
|
6月前
|
安全 JavaScript 前端开发
kotlin开发安卓app,JetPack Compose框架,给webview新增一个按钮,点击刷新网页
在Kotlin中开发Android应用,使用Jetpack Compose框架时,可以通过添加一个按钮到TopAppBar来实现WebView页面的刷新功能。按钮位于右上角,点击后调用`webViewState?.reload()`来刷新网页内容。以下是代码摘要:
|
6月前
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。
|
6月前
|
XML API 开发工具
Android Bitmap 加载与像素操作
Android Bitmap 加载与像素操作
49 2