在基类布局中加上一个全局的进度条,可能是比较简单的处理方式。
但是如果是为了更好的体验,我们可能需要在按钮点击位置,出现进度条。
出于这个想法,写了这个小工具,用法很简单,在需要显示进度条的view当作targertview传参进去就行了
hideTargetView使用来控制,进度条显示的时候,原来的view显示还是消失。
实现逻辑上,本来想不增加布局深度,想直接getDecorView从activity的viewTree中最近一个FrameLayout布局中,根据传参的view的位置的相同位置的放置一个progressbar,后来发现在我们布局中存在scrollview这种可以滚动的视图的时候,progressbar不会跟着一起滚动,挺尴尬。
然后才想到了这种替换当前布局为Framelayout的方式,但是这种方式也存在一个问题,就是在存在view间依赖的relativelayout等布局中会破坏视图间依赖,解决方式也很简单,我们编写布局的时候依赖之间的reference value传递的是id,那么我们把当前显示的view的id set到我们生成的Framelayout中就可以解决这个问题了。
public void showLoading(View v,boolean hideTargetView) { PgBarUtils.getInstance() .getBuilder(this) .targertView(v) .hideTargetView(hideTargetView) .show(); } public void hideLoadingView(View v) { PgBarUtils.getInstance() .getBuilder(this) .hide(v); } @Override protected void onDestroy() { super.onDestroy(); PgBarUtils.getInstance().destroyActivity(this); }
调用的地方通过单例工具获取对应view的progressbarBuilder实例。
不用担心对象重复庄创建的问题。
工具通过获取view作为key来进行progerssbar对象管理,没有则新建,有则获取。
另外记得在ondestroy中调用PgbarUtils的ondestroy方法来释放,对象就行了。
否则容易造成内存泄漏。
核心的实现代码在下面,有兴趣的可以看看,没兴趣看的直接拿去用好了,反正也就是个小工具。
import android.content.Context;import android.support.annotation.IntRange;import android.support.annotation.LayoutRes;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import android.widget.ProgressBar;import java.util.HashMap;import java.util.concurrent.atomic.AtomicReference;/** * Author : yizhihao (Merlin) * Create time : 2017-07-02 10:57 * contact : * 562536056@qq.com || yizhihao.hut@gmail.com * */public class PgBarUtils { public static class Builder{ public static final int NO_ID = -0x1; private View targetView; private Context context; private boolean hideTargetView; private int layoutId = NO_ID; private int mGravity; private Builder(){ hideTargetView = true; layoutId = NO_ID; mGravity = Gravity.CENTER; } /** * key :target view * view :injected progressbar */ private HashMapmBarStack = new HashMap<>(); public Builder layoutId(@LayoutRes int id){ layoutId = id; return this; } public Builder(Context context) { this.context = context; } public Builder targertView(View targetView){ this.targetView = targetView; return this; } /** * 当progressbar显示的时候是否,显示target view */ public Builder hideTargetView(boolean showTargetView) { this.hideTargetView = showTargetView; return this; } public Builder gravity(int gravity){ this.mGravity = gravity; return this; } public void show(){ ProgressBar bar = mBarStack.get(targetView); if(bar == null){ if(layoutId != NO_ID){ bar = (ProgressBar) LayoutInflater.from(context).inflate(layoutId,null); } if(bar == null) bar = new ProgressBar(context); bar.setTag(context.getClass().getName()); int size = Math.min(targetView.getWidth(),targetView.getHeight()); ViewGroup viewParent = (ViewGroup) targetView.getParent(); //replace target view with framelayout //then add target view and progressbar to the //new framelayout contianer viewParent.removeView(targetView); FrameLayout container = new FrameLayout(context); //当为相对布局或者其他组件之间存在依赖关系的时候,需要用容器布局 //替代他们的依赖,防止布局出现问题。 container.setId(targetView.getId()); container.setLayoutParams(targetView.getLayoutParams()); //add target view to the new container container.addView(targetView,new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); //create a progress bar and add to the new container FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(size,size); final int padding = DisplayUtils.dip2px(context,5); bar.setPadding(padding,padding,padding,padding); //progress bar 默认居target view的中间位置 switch (mGravity){ case Gravity.LEFT: if(targetView.getHeight() == size){ lp.leftMargin += (targetView.getWidth() - size) / 3; break; } case Gravity.RIGHT: if(targetView.getHeight() == size){ lp.leftMargin += (targetView.getWidth() - size) * 2 / 3; break; } case Gravity.TOP: if(targetView.getWidth() == size){ lp.topMargin += (targetView.getHeight() - size) / 3; break; } case Gravity.BOTTOM: if(targetView.getWidth() == size){ lp.topMargin += (targetView.getHeight() - size) * 2 / 3; break; } default: if(targetView.getWidth() > targetView.getHeight()){ lp.leftMargin += (targetView.getWidth() - size) / 2; }else{ lp.topMargin += (targetView.getHeight() - size) /2; } break; } container.addView(bar,lp); viewParent.addView(container); mBarStack.put(targetView,bar); } if(hideTargetView) targetView.setVisibility(View.INVISIBLE); bar.setVisibility(View.VISIBLE); } public void remove(){ mBarStack.clear(); mBarStack = null; } public void hide(View view){ view.setVisibility(View.VISIBLE); ProgressBar bar = mBarStack.get(view); if(bar != null) bar.setVisibility(View.GONE); } } private HashMap builders = new HashMap<>(); public void destroyActivity(Context context){ final Builder builder = builders.remove(context.getClass().getName()); if(builder != null) builder.remove(); } public Builder getBuilder(Context context){ Builder builder = builders.get(context.getClass().getName()); if(builder == null){ builder = new Builder(context); builders.put(context.getClass().getName(),builder); } return builder; } private static final AtomicReference INSTANCE = new AtomicReference (); private PgBarUtils(){} public static PgBarUtils getInstance() { for (; ;) { PgBarUtils current = INSTANCE.get(); if (current != null) { return current; } current = new PgBarUtils(); if (INSTANCE.compareAndSet(null, current)) { return current; } } }}