自定义viewAndroid学习Android知识

写一个多状态View

2017-07-13  本文已影响2795人  AmatorLee

在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

/**

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

上一篇下一篇

猜你喜欢

热点阅读