NetworkStateView:界面多状态加载

来源:互联网 发布:prolink ii软件下载 编辑:程序博客网 时间:2024/06/10 21:58

本文来自简书,原文地址:http://www.jianshu.com/p/858d41972d15

在项目中经常需要进行不同状态的加载,例如在网络请求时的加载中状态,加载失败状态,没有网络状态和没有数据的状态等,之前在项目中的做法是把几个不同的状态布局都添加到需要进行状态切换的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的方法就可以,至于怎么进行设置,请等下篇讲解。。。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 练科目三很紧张怎么办 驾照学员卡丢了怎么办 驾考时考试的车系统出错怎么办 驾驶证超期6个月怎么办 北京汽车年检只有电子保单怎么办 交电费户号9位数怎么办 扬州驾照12分扣完了怎么办 有大专毕业证在深圳怎么办居住证 微信解释包错误怎么办 富士康离职不批怎么办 到了怀孕年龄找不到工作怎么办 建筑公司挂靠发生人员伤残怎么办 外地生小孩落北京户口怎么办 户籍档案查不到直系亲属关系怎么办 考过了二建注册怎么办 异地工作辞职回家档案怎么办 离职怎么办档案放在人才市场 人才房住了6年后怎么办 医保辞职后断了怎么办 社保断了生育险怎么办 深圳小产权房水电费纠纷怎么办 有公租房的再婚怎么办 廉租房被没收了怎么办 商铺到期房东不续租怎么办 天津集体户口买不起房怎么办 房东不想续租了怎么办 唯一住房卖掉后户口怎么办 杭州唯一住房卖掉后户口怎么办 唯一一套住房卖掉户口怎么办 房租押金条丢了怎么办 二建证书跟毕业证丢失怎么办 住宅房到70年怎么办 护照号变了机票怎么办 苹果se指纹坏了怎么办 月经推迟怎么办才能快点来 车载支架不粘了怎么办 otpc平板电脑无法开机怎么办 手表表轴掉了怎么办 鸡肉放冰箱臭了怎么办 鸡胸肉熟了腥怎么办 梦幻西游手游手机号换了怎么办