在app开发过程中很多时候我们需要访问网络,访问数据库等,此时app将会有多种状态,比如加载中,加载成功,加载失败,没有网络等等,此时如果我们使用弹出的方式告知用户,非常不友好。之前被产品爸爸说有种笨重的感觉,但是笨重这么抽象你告诉我我TM该怎么理解呢?
经过leader的暗示解答,终于知道原来他想要那种感觉,就是那种看起来不笨重的感觉,翻译过来就是使用多状态,那么应该怎么做呢?看到过有人封装在BaseFragment和BaseActivity,但是这样子做耦合度太高,而且看起来代码也比较笨重,是的又回到了笨重这个话题。
效果演示
那么笨重feel是怎样的呢?
笨重feel那么一般我们应该怎么做呢?
看看下面的小图图:
整体结构
那么它的整体结构是怎样的呢?
整体结构从上面的整体结构i图可以知道主要有以下方法:
createView() 构造方法,这里重载了两个,分别使用默认的view以及使用you like view
onLoad() 加载方法,显示loadingview
onEmpty() 空数据,显示emptyView
onError() 加载出错,显示errorView
onNoNet() 没有网络,显示noNetView
onSuccess 加载成功,显示构造方法传入的contentView
onDestory() 资源回收
setOnRetryClick() 提供点击重新加载的接口
使用
使用方法很简单,根据上面的整体结构
- 构造
StatusViewManager manager = StatusViewManager.createView(Context, ContentView);
- 加载
manager.onLoad()
- 根据情况调用各种状态
代码实现
StatusViewManager
/**
* Created by AmatorLee on 2017/7/12.
*/
public class StatusViewManager extends StatusInterface implements View.OnClickListener {
private LayoutInflater mInflater;
/**
* 加载view
*/
private View mLoadView;
/**
* 错误view
*/
private View mErrorView;
/**
* 无数据view
*/
private View mEmptyView;
/**
* 实际view
*/
private View mContentView;
/**
* 无网络链接时得view
*/
private View mNoNetView;
private RelativeLayout.LayoutParams mParams;
/**
* 保存状态view的container
*/
private RelativeLayout mStatusContainer;
private Context mContext;
/**
* 避免重复添加
*/
private boolean isAddLoad, isAddEmpty, isAddNoNet, isAddError;
/**
* 可见状态
*/
public static final int V = View.VISIBLE;
/***
* 不可见状态
*/
public static final int G = View.GONE;
/**
* 重新加载接口
*/
private onRetryClick mOnRetryClick;
/**
* 切换到主线程改变view的状态
*/
private Handler mMainThreadHandler;
private int empty_layout_id = -1;
private int error_layout_id = -1;
private int no_net_layout_id = -1;
private int loading_layout_id = -1;
public static final String ERROR = "error";
public static final String EMPTY = "empty";
public static final String NONET = "nonet";
public static final String LOAD = "load";
public void setOnRetryClick(onRetryClick onRetryClick) {
mOnRetryClick = onRetryClick;
}
private StatusViewManager(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {
super();
this.loading_layout_id = loading_layout_id;
this.empty_layout_id = empty_layout_id;
this.error_layout_id = error_layout_id;
this.no_net_layout_id = no_net_layout_id;
mContentView = contentView;
mMainThreadHandler = new Handler(Looper.getMainLooper());
mContext = context;
mInflater = LayoutInflater.from(context);
mParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
mParams.addRule(RelativeLayout.CENTER_IN_PARENT);
initView();
setOnClick();
initContainer();
}
private void setOnClick() {
if (mEmptyView != null)
mEmptyView.setOnClickListener(this);
if (mNoNetView != null)
mNoNetView.setOnClickListener(this);
if (mErrorView != null)
mErrorView.setOnClickListener(this);
}
public static StatusViewManager createView(Context context, View ContentView) {
return new StatusViewManager(context, ContentView, -1, -1, -1, -1);
}
public static StatusViewManager createView(Context context, View contentView, int loading_layout_id, int empty_layout_id, int error_layout_id, int no_net_layout_id) {
return new StatusViewManager(context, contentView, loading_layout_id, empty_layout_id, error_layout_id, no_net_layout_id);
}
@Override
protected void initView() {
if (loading_layout_id == -1) {
loading_layout_id = R.layout.layout_loading;
}
if (empty_layout_id == -1) {
empty_layout_id = R.layout.layout_empty;
}
if (error_layout_id == -1) {
error_layout_id = R.layout.layout_error;
}
if (no_net_layout_id == -1) {
no_net_layout_id = R.layout.layout_no_net;
}
try {
mLoadView = mInflater.inflate(loading_layout_id, null);
mLoadView.setTag(LOAD);
mErrorView = mInflater.inflate(error_layout_id, null);
mErrorView.setTag(ERROR);
mEmptyView = mInflater.inflate(empty_layout_id, null);
mEmptyView.setTag(EMPTY);
mNoNetView = mInflater.inflate(no_net_layout_id, null);
mNoNetView.setTag(NONET);
} finally {
mInflater = null;
}
}
@Override
public void initContainer() {
mStatusContainer = new RelativeLayout(mContext);
mStatusContainer.setLayoutParams(mParams);
ViewGroup parent = (ViewGroup) mContentView.getParent();
parent.addView(mStatusContainer);
}
@Override
public void onLoad() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (mLoadView != null && !isAddLoad) {
isAddLoad = true;
mStatusContainer.addView(mLoadView, mParams);
}
show(STATUS.LOADING);
}
});
}
private void show(STATUS result) {
switch (result) {
case SUCCESS:
changeVisiable(V, G, G, G, G);
break;
case LOADING:
changeVisiable(G, V, G, G, G);
break;
case NONET:
changeVisiable(G, G, G, G, V);
break;
case ERROR:
changeVisiable(G, G, G, V, G);
break;
case EMPTY:
changeVisiable(G, G, V, G, G);
break;
}
}
private void changeVisiable(final int contentStatus, final int loadStatus, final int emptyStatus, final int errorStatus, final int nonetStatus) {
if (mContentView != null) {
mContentView.setVisibility(contentStatus);
}
if (mLoadView != null) {
mLoadView.setVisibility(loadStatus);
}
if (mEmptyView != null) {
mEmptyView.setVisibility(emptyStatus);
}
if (mNoNetView != null) {
mNoNetView.setVisibility(nonetStatus);
}
if (mErrorView != null) {
mErrorView.setVisibility(errorStatus);
}
}
@Override
public void onSuccess() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
show(STATUS.SUCCESS);
}
});
}
@Override
public void onNoNet() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddNoNet && mNoNetView != null) {
mStatusContainer.addView(mNoNetView, mParams);
isAddNoNet = true;
}
show(STATUS.NONET);
}
});
}
@Override
public void onError() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddError && mErrorView != null) {
mStatusContainer.addView(mErrorView, mParams);
isAddError = true;
}
show(STATUS.ERROR);
}
});
}
@Override
public void onEmpty() {
mMainThreadHandler.post(new Runnable() {
@Override
public void run() {
if (!isAddEmpty && mEmptyView != null) {
mStatusContainer.addView(mEmptyView, mParams);
isAddEmpty = true;
}
show(STATUS.EMPTY);
}
});
}
@Override
public void onClick(View view) {
if (mOnRetryClick != null) {
mOnRetryClick.onRetryLoad();
}
}
public enum STATUS {
LOADING,
EMPTY,
ERROR,
SUCCESS,
NONET
}
@Override
public void onDestory() {
isAddNoNet = false;
isAddEmpty = false;
isAddLoad = false;
isAddError = false;
mContext = null;
if (mLoadView != null) {
mLoadView = null;
}
if (mContentView != null) {
mContentView = null;
}
if (mEmptyView != null) {
mEmptyView = null;
}
if (mErrorView != null) {
mErrorView = null;
}
if (mNoNetView != null) {
mNoNetView = null;
}
if (mParams != null) {
mParams = null;
}
for (int i = 0; i < mStatusContainer.getChildCount(); i++) {
mStatusContainer.removeViewAt(i);
}
mStatusContainer = null;
}
interface onRetryClick {
void onRetryLoad();
}
}```
#####StatusInterface
/**
- Created by AmatorLee on 2017/7/12.
*/
public abstract class StatusInterface {
protected abstract void initView();
protected abstract void initContainer();
protected abstract void onLoad();
protected abstract void onSuccess();
protected abstract void onNoNet();
protected abstract void onError();
protected abstract void onEmpty();
protected abstract void onDestory();
}你可能会问为什么要提供一个
StatusInterface```,但是我不告诉你。
总结
现在流行的直播平台大都是这个小技巧,虽然简单但是常用,所有自己简单的写一下,如果你发现有bug,尽情反馈,同时我也会自我完善。
最后,provide a gayhub demo
网友评论