1.背景
开发中每个页面都需要提示用户加载中、网络错误和没有数据,那么每个Activity或者Fragment的布局中都需要写这三个布局,这样的话会导致XML文件显得很复杂。
有的同学说,那我可以用include标签呀。
好的,include标签确实可以解决引入三个状态导致XML臃肿的问题,可是,在实际需要展示的时候,代码会出现这样一种情况:
想想在每个Activity和Fragment都需要写这三个方法,对于这种不怕麻烦的行为,我只想说:我不要!
2.设计思路
无网,无数据布局实际上是对实际内容展示的一种交互扩展,原则上来说,状态布局和实际内容展示渲染在屏幕上的区域应该是一模一样的,那么,我们是否可以通过代码添加布局到这块区域来控制展示?
毫无疑问,可以。
这里必须提到一个类:LayoutParams,它里面存储了View在ViewGroup中位置信息的一系列参数,我们可以通过contentView.getLayoutParams()获取到内容展示布局所在ViewGroup中的位置,在这个位置上进行不同状态展示的操作。在这里我推荐使用一个ViewGroup存储Loading、NoData、NetError、Content这四个状态,在这个ViewGroup中操作状态的切换,而不是通过addView和removeView切换状态。
大致代码:
public class LoadingAndRetryLayout extends FrameLayout {
private View mLoadingView;
private View mRetryView;
private View mContentView;
private View mEmptyView;
public void setContentView(View view){
mContentView = view;
}
//..public void showContent() {
//..
}
//..
}
public class LoadingAndRetryManager {
public LoadingAndRetryManager(Object activityOrFragmentOrView,OnLoadingAndRetryListener listener) {
//..
View oldContent;
index = contentParent.findChild(oldContent);
LoadingAndRetryLayout loadingAndRetryLayout =new LoadingAndRetryLayout(context);
ViewGroup.LayoutParams lp =oldContent.getLayoutParams();
contentParent.addView(loadingAndRetryLayout, index,lp);
loadingAndRetryLayout.setContentView(oldContent);
//..
}
}
至此,我们可以通过LoadingAndRetryManager去控制四种状态view的展示。
3.使用
LoadingAndRetryManager mLoadingAndRetryManager =LoadingAndRetryManager.generate(view , new OnLoadingAndRetryListener({
@Override
public void setRetryEvent(View retryView) {
//...
}
});mLoadingAndRetryManager.showEmpty();
mLoadingAndRetryManager.showError();
mLoadingAndRetryManager.showLoading();
mLoadingAndRetryManager.showContent();
4.优缺点
缺点:增加一层View的层级,渲染上可能比实际耗时,但是用户使用上应该感觉不出来。
优点:对布局的侵入低,不用写重复的XML和大量的setVisibility,可以给同一页面不同View设置不同的状态展示,可灵活定制,强大的可扩展性,代码看起来更加优雅。
5.Demo链接
以下是根据刚才设计思路的简单封装: