咱们在开发过程中经常需要从网络上获取数据。这个时候为了增强用户体验。就可能有如下需求:在获取的数据的中时候显示加载中的UI(获取数据需要 一定的时间)、如果获取数据失败显示失败的UI、获取的数据为空的时候显示空数据的UI、数据成功获取到的时候才显示获取到的数据列表。总之一句话就是根据不同的状态现实不同的UI。这也是我们这篇文章的重点.接下来咱么就对这一需求做一个简单的封装。
推荐几篇实现该功能比较好的博客
Android中BaseActivity的简单使用,可以切换无数据、网络错误的界面
Android 加载成功、加载失败、加载中、无数据四个不同界面的切换
Android状态页切换(数据加载中,数据加载失败,空数据)
Android开发之常用的loading等待效果实现,仿微博等待动画。两种实现方式详解
方式1:封装到BaseActivity/BaseFragment中
一般来说,项目中都会有多个Activity或者Fragment,每个界面都会有一些相同的地方,比如标题栏、无数据界面、网络错误界面,每个界面都写就会显得很重复,也不便于维护。所以这个时候就有必要写一个基类来进行封装,也就是BaseActivity或者BaseFragment.
无数据和网络错误的情况。对于上边的标题栏,可能有多种情况,有标题栏,无标题栏,是否有返回按钮,右边是否显示文字或图片。这些情况我们都可以写在基类中。这些公用的界面都是写在BaseActivity的对应的xml文件中。
view_base_state_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="44dp"
android:gravity="center"
android:background="@color/white"
android:text="标题"
android:textColor="#000000"
android:textSize="18sp"
android:textStyle="bold" />
<!--加载进度条布局-->
<LinearLayout
android:id="@+id/view_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/title_bar"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="加载中..." />
</LinearLayout>
<!--请求成功布局-->
<FrameLayout
android:id="@+id/view_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/title_bar"></FrameLayout>
<!--请求数据为空,加载失败,无网络布局-->
<LinearLayout
android:id="@+id/view_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/title_bar"
android:gravity="center">
<TextView
android:id="@+id/text_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂无数据" />
</LinearLayout>
</RelativeLayout>
BaseActivity
/**
* Cerated by xiaoyehai
* Create date : 2020/11/11 12:14
* description :加载进度条,请求成功,请求数据为空,请求失败,无网络等状态不同界面的切换
*/
public abstract class BaseActivity extends AppCompatActivity {
private RelativeLayout mRootView;
private View mViewProgress;
private FrameLayout mViewContent;
private View mViewEmpty;
private TextView mTextTip;
private TextView mTvTitleBar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_base_state_layout);
findViews();
init();
}
public void initTitleBar(boolean isShow, String title) {
mTvTitleBar.setText(title);
if(isShow) {
mTvTitleBar.setVisibility(View.VISIBLE);
}else {
mTvTitleBar.setVisibility(View.GONE);
}
}
public void showProgressView() {
showView(R.id.view_progress);
}
public void showContentView() {
showView(R.id.view_content);
}
public void showEmptyView() {
showView(R.id.view_empty);
}
public void showEmptyView(int resId) {
showEmptyView();
mTextTip.setText(resId);
}
/**
* 请求数据为空,请求失败,无网络等状态都用同一个布局
*
* @param msg
*/
public void showEmptyView(String msg) {
showEmptyView();
mTextTip.setText(msg);
}
public void showView(int viewId) {
for (int i = 1; i < mRootView.getChildCount(); i++) {
if (mRootView.getChildAt(i).getId() == viewId) {
mRootView.getChildAt(i).setVisibility(View.VISIBLE);
} else {
mRootView.getChildAt(i).setVisibility(View.GONE);
}
}
}
private void findViews() {
mRootView = findViewById(R.id.rootView);
mTvTitleBar = findViewById(R.id.title_bar);
mViewProgress = findViewById(R.id.view_progress);
mViewContent = (FrameLayout) findViewById(R.id.view_content);
mViewEmpty = findViewById(R.id.view_empty);
mTextTip = (TextView) findViewById(R.id.text_tip);
mViewEmpty.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onReload();
}
});
//将当前界面的布局添加到BaseActivity中去
View realContentView = LayoutInflater.from(this).inflate(getLayoutId(), mViewContent, true);
}
public void onReload() {
}
protected abstract int getLayoutId();
protected abstract void init();
}
使用
public class SecondActivity extends BaseActivity {
@Override
protected int getLayoutId() {
return R.layout.activity_second;
}
@Override
protected void init() {
initTitleBar(true, "SecondActivity");
loadData();
}
//模拟加载数据
private void loadData() {
showProgressView();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
int code = 202;
switch (code) {
case 200:
showContentView();
break;
case 201:
showEmptyView("暂无数据");
break;
case 202:
showEmptyView("加载失败");
break;
case 203:
showEmptyView("无网络");
break;
}
}
}, 2000);
}
@Override
public void onReload() {
super.onReload();
loadData();
}
}
BaseFragment
public abstract class BaseFragment extends Fragment implements View.OnClickListener {
protected Context mContext;
private View mViews;
private FrameLayout mRootView;
private View mViewProgress;
private FrameLayout mViewContent;
private View mViewEmpty;
private TextView mTextTip;
private TextView mTvTitleBar;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mViews = inflater.inflate(R.layout.view_base_state_layout, container, false);
findViews();
return mViews;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRealContentView();
init();
}
public void initTitleBar(boolean isShow, String title) {
mTvTitleBar.setText(title);
if (isShow) {
mTvTitleBar.setVisibility(View.VISIBLE);
} else {
mTvTitleBar.setVisibility(View.GONE);
}
}
private void findViews() {
mRootView = mViews.findViewById(R.id.rootView);
mTvTitleBar = mViews.findViewById(R.id.title_bar);
mViewProgress = mViews.findViewById(R.id.view_progress);
mViewContent = (FrameLayout) mViews.findViewById(R.id.view_content);
mViewEmpty = mViews.findViewById(R.id.view_empty);
mTextTip = (TextView) mViews.findViewById(R.id.text_tip);
mViewEmpty.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onReload();
}
});
}
protected void onReload() {
}
private void setRealContentView() {
View realContentView = LayoutInflater.from(getActivity()).inflate(getLayoutId(), mViewContent, true);
}
public void showProgressView() {
showView(R.id.view_progress);
}
public void showContentView() {
showView(R.id.view_content);
}
public void showEmptyView() {
showView(R.id.view_empty);
}
public void showEmptyView(int resId) {
showEmptyView();
mTextTip.setText(resId);
}
public void showEmptyView(String msg) {
showEmptyView();
mTextTip.setText(msg);
}
public void showView(int viewId) {
for (int i = 1; i < mRootView.getChildCount(); i++) {
if (mRootView.getChildAt(i).getId() == viewId) {
mRootView.getChildAt(i).setVisibility(View.VISIBLE);
} else {
mRootView.getChildAt(i).setVisibility(View.GONE);
}
}
}
protected abstract int getLayoutId();
protected abstract void init();
}
方式2:自定义一个控件来切换布局
Android 加载成功、加载失败、加载中、无数据四个不同界面的切换
ViewStatusLayout
/**
* Cerated by xiaoyehai
* Create date : 2020/11/11 14:31
* description : 自定义一个View来切换布局。
*/
public class ViewStatusLayout {
private View mVEmptyContainer;
private ImageView mIvNoDataView;
private TextView mTvNoDataTip;
private TextView mTvRetryBtn;
public Builder mBuilder;
public View mRoot;
private View mClLoadingContainer;
/***
* 当前状态
*/
private @ViewStatus int mCurrentStatus;
private ViewStatusLayout(Context context, ViewGroup parent, Builder builder) {
if (builder == null) {
throw new RuntimeException("you must create commonNoDataLayout with Builder");
}
mBuilder = builder;
mRoot = LayoutInflater.from(context).inflate(R.layout.view_status_layout, parent);
mVEmptyContainer = parent.findViewById(R.id.ll_empty_container);
mIvNoDataView = parent.findViewById(R.id.iv_no_data_img);
mTvNoDataTip = parent.findViewById(R.id.tv_no_data_tip);
mTvRetryBtn = parent.findViewById(R.id.stv_retry);
mClLoadingContainer = parent.findViewById(R.id.cl_loading_container);
if (builder.background != 0) {
mVEmptyContainer.setBackgroundResource(builder.background);
}
switchView(mBuilder.viewStatus);
if (builder.listener == null) {
mTvRetryBtn.setVisibility(View.GONE);
} else {
mTvRetryBtn.setVisibility(View.VISIBLE);
if (!TextUtils.isEmpty(builder.retryTip)) {
mTvRetryBtn.setText(builder.getRetryTip());
}
mTvRetryBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
builder.listener.click(mCurrentStatus);
}
});
}
}
private void setNoDataView() {
mTvNoDataTip.setText(mBuilder.getNoDataTip());
mIvNoDataView.setImageResource(mBuilder.noDataResId);
if (TextUtils.isEmpty(mBuilder.getRetryTip())) {
mTvRetryBtn.setVisibility(View.GONE);
} else {
mTvRetryBtn.setVisibility(View.VISIBLE);
mTvRetryBtn.setText(mBuilder.getRetryTip());
}
}
private void setNoNetworkView() {
mTvNoDataTip.setText(mBuilder.getNoNetworkTip());
mIvNoDataView.setImageResource(mBuilder.getNoNetworkResId());
if (TextUtils.isEmpty(mBuilder.getNoNetworkBtnTip())) {
mTvRetryBtn.setVisibility(View.GONE);
} else {
mTvRetryBtn.setVisibility(View.VISIBLE);
mTvRetryBtn.setText(mBuilder.getNoNetworkBtnTip());
}
}
public void switchView(@ViewStatus int viewStatus) {
switch (viewStatus) {
case ViewStatus.HASDATA:
mVEmptyContainer.setVisibility(View.GONE);
mCurrentStatus &= ~ViewStatus.NODATA;
mCurrentStatus &= ~ViewStatus.NONETWORK;
mCurrentStatus &= ~ViewStatus.EMPTY;
mClLoadingContainer.setVisibility(View.GONE);
break;
case ViewStatus.NODATA:
if(mBuilder.useStatusView){
mVEmptyContainer.setVisibility(View.VISIBLE);
setNoDataView();
}
mCurrentStatus &= ~ViewStatus.HASDATA;
mCurrentStatus &= ~ViewStatus.NONETWORK;
mCurrentStatus &= ~ViewStatus.EMPTY;
mClLoadingContainer.setVisibility(View.GONE);
break;
case ViewStatus.NONETWORK:
if (((mCurrentStatus & 0xfff) & ViewStatus.HASDATA) == ViewStatus.HASDATA) {
return;
}
mCurrentStatus &= ~ViewStatus.HASDATA;
mCurrentStatus &= ~ViewStatus.NODATA;
mCurrentStatus &= ~ViewStatus.EMPTY;
mClLoadingContainer.setVisibility(View.GONE);
if(mBuilder.useStatusView) {
mVEmptyContainer.setVisibility(View.VISIBLE);
}
setNoNetworkView();
break;
case ViewStatus.LOADING_START:
mCurrentStatus &= ~ViewStatus.LOADING_END;
mClLoadingContainer.setVisibility(View.VISIBLE);
break;
case ViewStatus.LOADING_END:
mCurrentStatus &= ~ViewStatus.LOADING_START;
mClLoadingContainer.setVisibility(View.GONE);
break;
case ViewStatus.EMPTY:
mVEmptyContainer.setVisibility(View.GONE);
mCurrentStatus = viewStatus;
mClLoadingContainer.setVisibility(View.GONE);
break;
default:
break;
}
mCurrentStatus = mCurrentStatus | viewStatus;
}
public static class Builder {
private ViewGroup container;//父容器
private CharSequence noDataTip ;
private int noDataResId;
/***
* 重试按钮文案
*/
private CharSequence retryTip;
private IRetryClickListener listener;
private int noNetworkResId;
private int background;
private CharSequence noNetworkTip;
/***
* 无网络时的点击重试
*/
private CharSequence noNetworkBtnTip;
private @ViewStatus
int viewStatus = ViewStatus.EMPTY;
/***
* 是否使用状态图,有些页面不需要展示无数据也,无网络页
*/
private boolean useStatusView = true;
public Builder setBackground(int dr) {
this.background = dr;
return this;
}
public CharSequence getNoDataTip() {
return noDataTip;
}
public Builder setNoDataTip(CharSequence noDataTip) {
this.noDataTip = noDataTip;
return this;
}
public int getNoDataResId() {
return noDataResId;
}
public Builder setNoDataResId(int noDataResId) {
this.noDataResId = noDataResId;
return this;
}
public int getNoNetworkResId() {
return noNetworkResId;
}
public Builder setNoNetworkResId(int noNetworkResId) {
this.noNetworkResId = noNetworkResId;
return this;
}
public CharSequence getNoNetworkTip() {
return noNetworkTip;
}
public Builder setNoNetworkTip(CharSequence noNetworkTip) {
this.noNetworkTip = noNetworkTip;
return this;
}
public int getViewStatus() {
return viewStatus;
}
public Builder setViewStatus(int viewStatus) {
this.viewStatus = viewStatus;
return this;
}
public ViewGroup getContainer() {
return container;
}
public Builder setContainer(ViewGroup container) {
this.container = container;
return this;
}
public Builder setRetryClickListener(IRetryClickListener listener) {
this.listener = listener;
return this;
}
public IRetryClickListener getRetryClickListener() {
return listener;
}
public Builder setRetryTip(CharSequence tip) {
this.retryTip = tip;
return this;
}
public CharSequence getRetryTip() {
return retryTip;
}
public CharSequence getNoNetworkBtnTip() {
return noNetworkBtnTip;
}
public Builder setNoNetworkBtnTip(CharSequence noNetworkBtnTip) {
this.noNetworkBtnTip = noNetworkBtnTip;
return this;
}
public boolean isUseStatusView() {
return useStatusView;
}
public Builder setUseStatusView(boolean useStatusView) {
this.useStatusView = useStatusView;
return this;
}
public ViewStatusLayout attach() {
if (container == null) throw new RuntimeException("you must set container first");
return new ViewStatusLayout(container.getContext(), container, this);
}
}
public interface IRetryClickListener {
void click(@ViewStatus int viewStatus);
}
}
view_status_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll_empty_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/iv_no_data_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintVertical_bias="0.2"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/empty_order_list"
app:layout_constraintBottom_toTopOf="@id/tv_no_data_tip"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/tv_no_data_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="15sp"
tools:text="暂无数据"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_no_data_img"
app:layout_constraintBottom_toTopOf="@+id/stv_retry"/>
<Button
android:id="@+id/stv_retry"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center"
android:textSize="16sp"
android:textColor="@color/white"
android:text="重试"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_no_data_tip"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_loading_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="visible"
android:visibility="gone">
<TextView
android:id="@+id/rtv_loading_bg"
android:layout_width="120dp"
android:layout_height="0dp"
android:background="@drawable/shape_solid_alpha_4"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="#EA392C"
android:indeterminateTintMode="src_atop"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="@id/rtv_loading_bg"
app:layout_constraintStart_toStartOf="@id/rtv_loading_bg"
app:layout_constraintBottom_toTopOf="@id/tv_loading_tip"
app:layout_constraintEnd_toEndOf="@id/rtv_loading_bg"/>
<TextView
android:id="@+id/tv_loading_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="加载中..."
android:textColor="#333333"
android:textSize="14sp"
android:singleLine="true"
app:layout_constraintTop_toBottomOf="@id/progress"
app:layout_constraintBottom_toBottomOf="@id/rtv_loading_bg"
app:layout_constraintStart_toStartOf="@id/rtv_loading_bg"
app:layout_constraintEnd_toEndOf="@id/rtv_loading_bg"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
ViewStatus
@IntDef({ViewStatus.EMPTY,ViewStatus.HASDATA, ViewStatus.NODATA,
ViewStatus.NONETWORK, ViewStatus.LOADING_START, ViewStatus.LOADING_END})
@Retention(RetentionPolicy.SOURCE)
public @interface ViewStatus {
int HASDATA = 0x01;
int NODATA = 0x02;
int NONETWORK = 0x04;
int LOADING_START = 0x08;
int LOADING_END = 0x10;
int EMPTY = 0x20;
}
ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="view_status_container" />
<item type="id" name="ctb_title" />
</resources>
BaseActivity
public abstract class BaseActivity2 extends AppCompatActivity {
protected ViewStatusLayout mViewStatusLayout;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
init();
initViewStatusLayout();
initData();
}
/***
* 是否需要全局空数据页
*/
protected boolean needViewStatus() {
return true;
}
private void initViewStatusLayout() {
if (!needViewStatus()) {
return;
}
if (mViewStatusLayout != null) {
return;
}
ViewStatusLayout.Builder builder = createViewStatusBuilder();
if (builder.getContainer() == null) {
ViewGroup vp = getViewStatusParent();
builder.setContainer(vp); //设置ViewStatusLayout的父容器
}
if (builder.getContainer() != null) {
mViewStatusLayout = builder.attach();
}
}
protected ViewStatusLayout.Builder createViewStatusBuilder() {
return new ViewStatusLayout.Builder()
.setNoDataTip("暂无数据")
.setNoDataResId(R.mipmap.empty_order_list)
.setNoNetworkTip("无网络,请先检查网络连接")
.setNoNetworkResId(R.mipmap.no_network)
.setNoNetworkBtnTip("点击重试");
}
/**
* 获取ViewStatusLayout的父容器
*
* @return
*/
protected ViewGroup getViewStatusParent() {
//如果子类Activity 指定了具体容器,则直接加载到此容器中
ViewGroup viewStatusContainer = findViewById(R.id.view_status_container);
Log.e("xyh", "getViewStatusParent: "+viewStatusContainer );
if (viewStatusContainer != null) {
return viewStatusContainer;
}
ViewGroup content = findViewById(android.R.id.content);
if (content.getChildCount() == 0) {
return content;
}
//rootV就是子类 Activity 自己定义的根布局
View rootV = content.getChildAt(0); //LinearLayout
//如果子布局不是viewgroup直接加载到content布局中
if (!(rootV instanceof ViewGroup)) {
return content;
}
ViewGroup firstVp = (ViewGroup) rootV; //LinearLayout
//如果根布局下没有别的控件,则加载到跟布局中
if (firstVp.getChildCount() == 0) {
return firstVp;
}
//标题栏
ViewParent ctb = firstVp.findViewById(R.id.ctb_title); //RelativeLayout
if (ctb != null) {
return createStatusView(firstVp);
} else {
return firstVp;
}
}
private FrameLayout createStatusView(ViewGroup rootV) {
FrameLayout container = new FrameLayout(this);
container.setId(R.id.view_status_container);
ViewGroup.LayoutParams lp;
if (rootV instanceof ConstraintLayout) {
ConstraintLayout.LayoutParams clp = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.MATCH_PARENT);
clp.topToBottom = R.id.ctb_title;
clp.bottomToBottom = rootV.getId();
clp.startToStart = rootV.getId();
lp = clp;
} else if (rootV instanceof RelativeLayout) {
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
rlp.addRule(RelativeLayout.BELOW, R.id.ctb_title);
lp = rlp;
} else {
lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
rootV.addView(container, lp);
return container;
}
public void showDialog(String title) {
if (mViewStatusLayout != null) {
mViewStatusLayout.switchView(ViewStatus.LOADING_START);
}
}
public void dismissDialog() {
if (mViewStatusLayout != null) {
mViewStatusLayout.switchView(ViewStatus.LOADING_END);
}
}
protected abstract int getLayoutId();
protected abstract void init();
protected abstract void initData();
}
使用
public class ThirdActivity extends BaseActivity2 {
private TextView mTvContent;
private FrameLayout mFlContainer;
@Override
protected int getLayoutId() {
return R.layout.activity_third;
}
@Override
protected void init() {
//mFlContainer = findViewById(R.id.fl_container);
mTvContent = findViewById(R.id.tv_content);
}
@Override
protected ViewStatusLayout.Builder createViewStatusBuilder() {
return super.createViewStatusBuilder()
//.setContainer(mFlContainer) //设置父容器
//.setUseStatusView(false) //是否使用状态图,有些页面不需要展示无数据页,无网络页
.setNoDataTip("暂时没有数据哦")
.setRetryTip("重新加载")
.setRetryClickListener(new ViewStatusLayout.IRetryClickListener() {
@Override
public void click(int viewStatus) {
loadData();
}
});
}
@Override
protected void initData() {
loadData();
}
//模拟加载数据
private void loadData() {
mViewStatusLayout.switchView(ViewStatus.LOADING_START);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
int code = 202;
switch (code) {
case 200:
mViewStatusLayout.switchView(ViewStatus.HASDATA);
mTvContent.setText("content");
break;
case 201:
mViewStatusLayout.switchView(ViewStatus.NODATA);
break;
case 202:
mViewStatusLayout.switchView(ViewStatus.NONETWORK);
break;
case 203:
mViewStatusLayout.switchView(ViewStatus.EMPTY);
break;
}
}
}, 2000);
}
}
activity_third.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ThirdActivity">
<RelativeLayout
android:id="@+id/ctb_title"
android:layout_width="match_parent"
android:layout_height="44dp">
<TextView
android:layout_width="match_parent"
android:layout_height="44dp"
android:gravity="center"
android:text="标题"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_below="@id/ctb_title"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18sp" />
</RelativeLayout>
</RelativeLayout>
还可以在activity_third.xml加上FrameLayout,id写死为view_status_container,其他都不变
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ThirdActivity">
<RelativeLayout
android:id="@+id/ctb_title"
android:layout_width="match_parent"
android:layout_height="44dp">
<TextView
android:layout_width="match_parent"
android:layout_height="44dp"
android:gravity="center"
android:text="标题"
android:layout_centerInParent="true"
android:textSize="18sp"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_below="@id/ctb_title"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18sp" />
</RelativeLayout>
<FrameLayout
android:layout_below="@id/ctb_title"
android:id="@+id/view_status_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
如果FrameLayout的id不是view_status_container,要在代码中设置父容器:
<FrameLayout
android:layout_below="@id/ctb_title"
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
@Override
protected void init() {
mFlContainer = findViewById(R.id.fl_container);
}
@Override
protected ViewStatusLayout.Builder createViewStatusBuilder() {
return super.createViewStatusBuilder()
.setContainer(mFlContainer) //设置父容器
//.setUseStatusView(false) //是否使用状态图,有些页面不需要展示无数据页,无网络页
.setNoDataTip("暂时没有数据哦")
.setRetryTip("重新加载")
.setRetryClickListener(new ViewStatusLayout.IRetryClickListener() {
@Override
public void click(int viewStatus) {
loadData();
}
});
}
BaseFragment
public class BaseFragment2 extends Fragment {
protected ViewStatusLayout mViewStatusLayout;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViewStatusLayout(getView());
}
/***
* 是否需要全局空数据页
*/
protected boolean needViewStatus(){
return true;
}
private void initViewStatusLayout(View view){
if(!needViewStatus()) {
return;
}
if(mViewStatusLayout != null ) {
return;
}
ViewStatusLayout.Builder builder = createViewStatusBuilder();
if(builder.getContainer() == null){
ViewGroup vp = getViewStatusParent(view);
builder.setContainer(vp);
}
if (builder.getContainer() != null) {
mViewStatusLayout = builder.attach();
}
}
protected ViewStatusLayout.Builder createViewStatusBuilder(){
return new ViewStatusLayout.Builder()
.setNoDataTip("没有找到相关内容~")
.setNoDataResId(R.mipmap.empty_order_list)
.setNoNetworkTip("网络不稳定,请重试")
.setNoNetworkResId(R.mipmap.no_network);
}
protected ViewGroup getViewStatusParent(View view) {
//如果指定了具体容器,则直接加载到此容器中
ViewGroup viewStatusContainer = view.findViewById(R.id.view_status_container);
if (viewStatusContainer != null) {
return viewStatusContainer;
}
if(!(view instanceof ViewGroup) || view instanceof ScrollingView) {
return null;
}
viewStatusContainer = (ViewGroup)view;
//如果跟布局下没有别的控件,则加载到跟布局中
if (viewStatusContainer.getChildCount() == 0) {
return viewStatusContainer;
}
ViewParent ctb = viewStatusContainer.findViewById(R.id.ctb_title);
if (ctb != null) {
return createStatusView(viewStatusContainer);
} else {
return viewStatusContainer;
}
}
private FrameLayout createStatusView(ViewGroup rootV) {
if(getContext() == null) {
return null;
}
FrameLayout container = new FrameLayout(getContext());
container.setId(R.id.view_status_container);
ViewGroup.LayoutParams lp;
if (rootV instanceof ConstraintLayout) {
ConstraintLayout.LayoutParams clp = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT);
clp.topToBottom = R.id.ctb_title;
clp.startToStart = rootV.getId();
lp = clp;
} else if (rootV instanceof RelativeLayout) {
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
rlp.addRule(RelativeLayout.BELOW, R.id.ctb_title);
lp = rlp;
} else {
lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
rootV.addView(container, lp);
return container;
}
public void showDialog(String title) {
if (mViewStatusLayout != null) {
mViewStatusLayout.switchView(ViewStatus.LOADING_START);
}
}
public void dismissDialog() {
if (mViewStatusLayout != null) {
mViewStatusLayout.switchView(ViewStatus.LOADING_END);
}
}
}