写一个多状态View

在app开发过程中很多时候我们需要访问网络,访问数据库等,此时app将会有多种状态,比如加载中,加载成功,加载失败,没有网络等等,此时如果我们使用弹出的方式告知用户,非常不友好。之前被产品爸爸说有种笨重的感觉,但是笨重这么抽象你告诉我我TM该怎么理解呢?
经过leader的暗示解答,终于知道原来他想要那种感觉,就是那种看起来不笨重的感觉,翻译过来就是使用多状态,那么应该怎么做呢?看到过有人封装在BaseFragment和BaseActivity,但是这样子做耦合度太高,而且看起来代码也比较笨重,是的又回到了笨重这个话题。

效果演示

那么笨重feel是怎样的呢?

笨重feel

那么一般我们应该怎么做呢?
看看下面的小图图:

status

整体结构

那么它的整体结构是怎样的呢?

整体结构

从上面的整体结构i图可以知道主要有以下方法:

createView()  构造方法,这里重载了两个,分别使用默认的view以及使用you like view
onLoad()      加载方法,显示loadingview
onEmpty()     空数据,显示emptyView
onError()     加载出错,显示errorView
onNoNet()     没有网络,显示noNetView
onSuccess     加载成功,显示构造方法传入的contentView
onDestory()   资源回收
setOnRetryClick()  提供点击重新加载的接口

使用

使用方法很简单,根据上面的整体结构

  1. 构造StatusViewManager manager = StatusViewManager.createView(Context, ContentView);
  2. 加载manager.onLoad()
  3. 根据情况调用各种状态

代码实现

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容