快速开发之统一界面管理类
在开发中我们总是要根据不同的状态,向用户展示不同的界面。比如说刚进入某个界面时,需要链接网络将请求的数据展示给用户,我们总不能直接给用户显示个大白板,然后等数据请求下来后再显示给用户吧。这时候我们就需要给用户展示一个正在加载的界面,然后等数据加载完成后,再切换界面,给用户展示加载成功后的内容界面;当然有时候请求数据失败,也不能直接显示个大白板吧,这时候就需要给用户显示一个提示界面,告诉用户数据加载失败了,然后点击重新加载。有的根据业务需求,可能显示给用户的界面还比这多。在这里也就三种状态对应三种界面,正在加载、加载成功、加载失败,在开发中为了统一风格,一般正在加载和加载失败的界面都是一样。那么怎么在xml中布局呢,我们肯定不会在每个xml来写一遍正在加载,加载失败的布局吧,这样显的布局文件也太乱了太臃肿了吧,为了复用,我们会将正在加载和加载失败的布局写出去,然后用include标签进行引用。但是发现了没,布局文件做到了复用,但是在每个界面中我们都要根据加载情况去展示某个布局和隐藏其他布局的逻辑还得写一遍,好吧,那我们把这套界面切换逻辑写到基类中吧,这样就可以减少很多重复代码了,但是这样好么,java的三大特性之一是什么,封装!对,为什么不封装起来使用呢。
代码部分
public class MulitStatuView extends FrameLayout{
private View view_loading ; // 正在加载中
private View view_content ; // 加载成功显示的界面
private View view_error ; // 加载失败显示的界面
private Statu currentStatu = Statu.STATU_LOADING ; // 默认为正在加载状态
private OnReLoadClickListener mReloadListener ; // 重新加载监听
private enum Statu{
STATU_LOADING, //正在加载
STATU_FINISH, //加载完成
STATU_ERROR, // 加载错误
}
public MulitStatuView(Context context) {
this(context,null);
}
public MulitStatuView(Context context, AttributeSet attrs) {
this(context, attrs ,0);
}
public MulitStatuView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context , attrs);
}
private void initView(Context context, AttributeSet attrs){
LayoutInflater inflater = LayoutInflater.from(context);
TypedArray typedArray = context.obtainStyledAttributes(attrs , R.styleable.MulitStatuView);
int layout_load_redId = typedArray.getResourceId(R.styleable.MulitStatuView_view_load , R.layout.view_loading_default);
int layout_error_redId = typedArray.getResourceId(R.styleable.MulitStatuView_view_error , R.layout.view_error_default);
view_error = inflater.inflate(layout_error_redId , null);
view_loading = inflater.inflate(layout_load_redId , null);
this.addView(view_error);
this.addView(view_loading);
if(typedArray.hasValue(R.styleable.MulitStatuView_view_content)){
int layout_content_redId = typedArray.getResourceId(R.styleable.MulitStatuView_view_content , R.layout.view_content_default);
view_content = inflater.inflate(layout_content_redId , null);
this.addView(view_content);
}
typedArray.recycle();
view_error.setOnClickListener(errorClickListener);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if(view_content == null){
view_content = findViewById(R.id.view_content);
}
showLoading();
}
/**
* 设置正在加载的view
* @param loadingView
*/
public void setLoadingView(View loadingView){
if(view_loading != null)
this.removeView(view_loading);
this.addView(loadingView);
this.view_loading = loadingView ;
}
/**
* 设置显示内容的View
* @param contentView
*/
public void setContentView(View contentView){
if(view_content != null)
this.removeView(view_content);
this.addView(contentView);
view_content = contentView ;
}
/**
* 设置加载失败的view
* @param errorView
*/
public void setErrorView(View errorView){
if(view_error != null)
this.removeView(view_error);
this.addView(errorView);
view_error = errorView ;
}
/**
* 加载成功后显示要展示的内容
*/
public void showContent(){
currentStatu = Statu.STATU_FINISH ;
showView();
}
/**
* 显示加载失败的view
*/
public void showError(){
currentStatu = Statu.STATU_ERROR ;
showView();
}
/**
* 显示正在加载状态view
*/
public void showLoading(){
currentStatu = Statu.STATU_LOADING ;
showView();
}
/**
* 根据状态显示view
*/
private void showView(){
hideAllView();
showViewByStatus();
}
/**
* 隐藏所有view
*/
private void hideAllView(){
view_error.setVisibility(View.GONE);
view_loading.setVisibility(View.GONE);
if(view_content != null)
view_content.setVisibility(View.GONE);
}
/**
* 根据状态切换界面
*/
private void showViewByStatus(){
switch (currentStatu){
case STATU_LOADING:
view_loading.setVisibility(View.VISIBLE);
break;
case STATU_ERROR:
view_error.setVisibility(View.VISIBLE);
break;
case STATU_FINISH:
if(view_content != null)
view_content.setVisibility(View.VISIBLE);
break;
}
}
/**
* 当加载失败时,设置重新加载监听
* @param reloadListener
*/
public void setReloadListener(OnReLoadClickListener reloadListener){
if(reloadListener == null){
throw new IllegalArgumentException("OnReloadClickListener shouldn't be null");
}
this.mReloadListener = reloadListener ;
}
public interface OnReLoadClickListener{
void onReLoadClickListener();
}
/**
* 加载失败后,点击重新加载的监听
*/
private View.OnClickListener errorClickListener = new View.OnClickListener(){
@Override
public void onClick(View v) {
showLoading();
mReloadListener.onReLoadClickListener();
}
};
}
如何使用呢
//1.直接在XML中布局 , 注意MulitStatuView里面只能包含一个View用来显示内容,而且这个View的id必须是*view_content*,
<com.zy.mulitstatuviewdemo.view.MulitStatuView
android:id="@+id/multiStatuView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/view_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="ContentView"
android:gravity="center"
android:textSize="18dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</com.zy.mulitstatuviewdemo.view.MulitStatuView>
//2. 或者这样布局,
<com.zy.mulitstatuviewdemo.view.MulitStatuView
android:id="@+id/multiStatuView"
app:view_content="@layout/view_content_default"
app:view_error="@layout/view_error_default"
app:view_load="@layout/view_loading_default"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.zy.mulitstatuviewdemo.view.MulitStatuView>
//3. 当然还可以这样在XML什么都不写,然后再代码中通过调用setErrorView();setLoadingView();setContentView()来设置正在加载,加载失败,加载成功的布局,
//4. 布局填充完成以后,在代码中通过调用showContent(),showError(),showLoading()就可以切换显示不同的布局了。
下面就是效果图了