NetworkStateView:界面多状态加载

来源:互联网 发布:手游矩阵 编辑:程序博客网 时间:2024/06/01 14:03

在项目中经常需要进行不同状态的加载,例如在网络请求时的加载中状态,加载失败状态,没有网络状态和没有数据的状态等,之前在项目中的做法是把几个不同的状态布局都添加到需要进行状态切换的Activity或Fragment的布局文件当中,接着再对每一个状态界面进行相应的隐藏显示,但是在界面一多的情况下,重复操作就会显得很繁琐。

在进行了无数次这样繁琐的操作后,有些受不了了,就想着能不能把这几种状态都封装到同一个View中,在需要显示不同的状态时只需要调用相应的状态方法就可以进行切换,这样可比上一种方法简便得多,哈哈,这当然是可以的,接下来就介绍一下NetworkStateView

NetworkStateView继承自LinearLayout,在里面定义了加载成功,加载中,加载出错(这里只统一定义为网络出错,当然了用在哪种出错方式上可以由你自己决定),没有网络,没有数据五种状态,其中加载成功表示用来显示Activity或Fragment的界面,并用变量mCurrentState来记住当前显示的状态,相应的变量值如下:

//当前的加载状态private int mCurrentState;private static final int STATE_SUCCESS = 0;private static final int STATE_LOADING = 1;private static final int STATE_NETWORK_ERROR = 2;private static final int STATE_NO_NETWORK = 3;private static final int STATE_EMPTY = 4;

接着需要自定义属性,用于传入对应的状态布局文件,在同一种状态中如果需要有不同的界面显示,便可以对应的传入layout文件,这样可以方便扩展

<declare-styleable name="NetworkStateView">    <!-- 加载中的布局id -->    <attr name="loadingView" format="reference" />    <!-- 加载错误的布局id -->    <attr name="errorView" format="reference" />    <!-- 加载错误的布局图片 -->    <attr name="nsvErrorImage" format="reference" />    <!-- 加载错误的布局文字 -->    <attr name="nsvErrorText" format="string" />    <!-- 没有数据的布局id -->    <attr name="emptyView" format="reference" />    <!-- 没有数据的布局图片 -->    <attr name="nsvEmptyImage" format="reference" />    <!-- 没有数据的布局文字 -->    <attr name="nsvEmptyText" format="string" />    <!-- 没有网络的布局id -->    <attr name="noNetworkView" format="reference" />    <!-- 没有数据的布局图片 -->    <attr name="nsvNoNetworkImage" format="reference" />    <!-- 没有数据的布局文字 -->    <attr name="nsvNoNetworkText" format="string" />    <!-- 刷新的ImageView图片id -->    <attr name="nsvRefreshImage" format="reference"/>    <!-- 文字大小 -->    <attr name="nsvTextSize" format="dimension" />    <!-- 文字颜色 -->    <attr name="nsvTextColor" format="color" /></declare-styleable>

定义了属性之后,需要在NetworkStateView的构造函数中使用TypedArray进行相应属性值的查找,注意,这里查找得到时布局文件的id,最后在显示的时候需要对布局文件id进行相应的inflate,查找之后可以进行一些基本属性的设置,例如LayoutParamsBackgroundColor

public NetworkStateView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {    super(context, attrs, defStyleAttr);    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NetworkStateView, defStyleAttr, 0);    mLoadingViewId = typedArray.getResourceId(R.styleable.NetworkStateView_loadingView, R.layout.view_loading);    mErrorViewId = typedArray.getResourceId(R.styleable.NetworkStateView_errorView, R.layout.view_network_error);    mNoNetworkViewId = typedArray.getResourceId(R.styleable.NetworkStateView_noNetworkView, R.layout.view_no_network);    mEmptyViewId = typedArray.getResourceId(R.styleable.NetworkStateView_emptyView, R.layout.view_empty);   ....    typedArray.recycle();    mInflater = LayoutInflater.from(context);    params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);    setBackgroundColor(getResources().getColor(R.color.white));}

在使用属性时,可以直接在NetworkStateView的布局文件中进行设置,又或者在styles文件中进行设置

  • 直接在布局文件中声明

      <com.zht.networkstateview.ui.widget.NetworkStateView xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      android:id="@+id/nsv_state_view"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:layout_centerInParent="true"      android:orientation="vertical"      android:visibility="visible"      app:emptyView="@layout/view_empty"      app:errorView="@layout/view_network_error"      app:loadingView="@layout/view_loading"      app:noNetworkView="@layout/view_no_network"      app:nsvTextColor="@color/gray_text_default"      app:nsvTextSize="16sp">  </com.zht.networkstateview.ui.widget.NetworkStateView>
  • 在styles文件进行设置

      <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">      <!-- Customize your theme here. -->      <item name="styleNetworkStateView">@style/NetworkStateViewTheme</item>      ...  </style>  <style name="NetworkStateViewTheme" parent="NetworkStateView.Style">      <item name="nsvTextSize">16sp</item>      <item name="nsvTextColor">#ffffff</item>      ...  </style>

进行上面的步骤后,就可以加载相应的布局文件了,以加载失败(网络出错)为例,先定义一个showError方法,在一开始需要将当前状态置为STATE_NETWORK_ERROR,接着inflate布局,注意,inflate之后需要进行addView将加载失败(网络出错)状态的View添加到NetworkStateView中,这样才可以进行相应的显示隐藏操作

public void showError() {    mCurrentState = STATE_NETWORK_ERROR;    if (null == mErrorView) {        mErrorView = mInflater.inflate(mErrorViewId, null);        addView(mErrorView, 0, params);    }    showViewByState(mCurrentState);}

showViewByState方法就是根据当前的状态来进行相应的View的切换

private void showViewByState(int state) {    //如果当前状态为加载成功,隐藏此View,反之显示    this.setVisibility(state == STATE_SUCCESS ? View.GONE : View.VISIBLE);    if (null != mLoadingView) {        mLoadingView.setVisibility(state == STATE_LOADING ? View.VISIBLE : View.GONE);    }    if (null != mErrorView) {        mErrorView.setVisibility(state == STATE_NETWORK_ERROR ? View.VISIBLE : View.GONE);    }    if (null != mNoNetworkView) {        mNoNetworkView.setVisibility(state == STATE_NO_NETWORK ? View.VISIBLE : View.GONE);    }    if (null != mEmptyView) {        mEmptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE : View.GONE);    }}

嗯...到这里其实也差不多了,不过还有一个问题,就是在加载失败之后需要进行刷新重新请求网络怎么办?哈哈,这当然也是可以解决的,我们只需要在定义一个刷新按钮,并对外提供一个接口进行调用就可以了,相应的接口及方法为

public void setOnRefreshListener(OnRefreshListener listener) {    mRefreshListener = listener;}public interface OnRefreshListener {    void onRefresh();}

那么showError可以改造如下

public void showError() {    mCurrentState = STATE_NETWORK_ERROR;    if (null == mErrorView) {        mErrorView = mInflater.inflate(mErrorViewId, null);        View errorRefreshView = mErrorView.findViewById(R.id.error_refresh_view);        if (null != errorRefreshView) {            errorRefreshView.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View view) {                    if (null != mRefreshListener) {                        mRefreshListener.onRefresh();                    }                }            });        }        addView(mErrorView, 0, params);    }    showViewByState(mCurrentState);}

嗯,这样就可以把多种状态的View统一封装在同一个View当中,我们可以在Activity的布局文件中通过include标签加入NetworkStateView,接着我们只要调用NetworkStateView的相关方法就可以进行多种状态的切换了

详细的代码以及Sample可以去我的github查看,觉得还可以的不妨Star或follow

古语有云:不懒的程序员不是好程序员,有人会觉得这样也只是比第一种方法稍微简便一些,但也是需要在每个界面的布局文件中通过include标签进行添加,并且进行findViewById的操作然后才能调用相关方法,能不能进行统一的设置呢?可以不需要在每个界面中进行include,统一设置之后就可以调用相关方法,这当然也是可以的,我们可以在BaseActivity进行相应的设置,这样子类Activity只需要调用BaseActivity的方法就可以,

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两年义务兵完了想继续当兵怎么办 保研联系老师说名额已满怎么办 在部队报函授不发毕业证怎么办 济南自考信息修改后原成绩怎么办 自考本科档案一直在自己手里怎么办 想考警校可身高差两公分怎么办 没读完初中现在想继续夜大怎么办 美国签证确认页姓和名写错了怎么办 单位不承认非法辞退说我旷工怎么办 工作了和同事在一起住宿舍怎么办 教会的事情商量是起冲突怎么办 转转购买的产品是坏的怎么办 二年级的学生反应太迟钝怎么办? 特别胖的人运动一半体力不支怎么办 怀孕了在胸透门口站了很久怎么办 自己觉的色弱但高考体检正常怎么办 高考体检不合格怎么办会影响录取吗 老婆起诉我离婚我不想离怎么办 中考结束了成绩差的学生怎么办 我儿了眼角模不好了怎么办 打了2次催产针没反应怎么办 高中体检学生隐私被同学看到怎么办 要出去旅游刚好遇上月经期怎么办 兵检的时候还在高中怎么办 人流后带上环20天白带很黄怎么办 武警义务兵训练的时候没合格怎么办 小孩考试考的不好·家长怎么办 怀孕了不小心碰了屁股疼怎么办 新密职教中心开学军训有点慌怎么办 房产证是士兵证办的退伍后怎么办 士兵证办的银行卡退伍了怎么办 看左上牙后引发上颌窦炎怎么办 老板克扣进件加班工资应该怎么办 医生给婴儿按嘴巴碰到喉咙痛怎么办 事故逃逸人死对方要钱太多怎么办 毕业工作未满一年辞职档案怎么办 淘宝上买的东西客服不理怎么办 蚂蚁借呗还款后没显示还款怎么办 王者荣耀什么英雄都打的很烂怎么办 军校参加了政审体检误了怎么办 如果老板搬迁不给工人补偿怎么办