1. 效果图
2. 自定义View –StateLayout(封装了4种状态的View:正在加载、加载失败、没有数据、正常界面)
/**
* 封装了4种状态的View:正在加载、加载失败、没有数据、正常界面
* @author dzl
*/
public class StateLayout extends FrameLayout {
private View loadingView;
private View failView;
private View emptyView;
private View contentView;
/** 包含了3种状态(正在加载、加载失败、没有数据) 的一个容器 */
private FrameLayout container;
public StateLayout(Context context) {
super(context);
// 创建出来的容器已经包含了3种状态:正在加载、加载失败、没有数据
container = (FrameLayout) View.inflate(this.getContext(), R.layout.state_layout, null);
// 查找出3种状态对应的View
loadingView = container.findViewById(R.id.loadingView);
failView = container.findViewById(R.id.failView);
emptyView = container.findViewById(R.id.emptyView);
showLoadingView();
this.addView(container);
}
/** 显示“正在加载。。。” */
public void showLoadingView() {
showView(loadingView);
}
/** 显示“加载失败” */
public void showFailView() {
showView(failView);
}
/** 显示“加载为空” */
public void showEmptyView() {
showView(emptyView);
}
/** 显示“正常加载到数据”的界面的View */
public void showContentView() {
showView(contentView);
}
/** 设置“正常状态的View” */
public void setContentView(int layoutResId) {
View contentView = View.inflate(getContext(), layoutResId, null);
this.setContentView(contentView);
}
/** 设置“正常状态的View” */
public void setContentView(View contentView) {
this.contentView = contentView;
container.addView(contentView);
contentView.setVisibility(View.GONE); // 默认不显示,默认显示的是LoadingView
}
/** 指示指定的View,并隐藏其它的View */
private void showView(View view) {
// System.out.println("childCount = " + container.getChildCount());
for (int i = 0; i < container.getChildCount(); i++) {
View child = container.getChildAt(i);
child.setVisibility(child == view ? View.VISIBLE : View.GONE);
}
}
}
自定义界面需要的布局文件
该文件已经包含三种状态(失败,空内容,加载中),正常显示界面,通过上面暴露出来的setContentView(id/View)接口来让用户自定义布局,即可给自定义界面增添第四种状态。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/failView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error_page"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载失败,点击重试"
android:textSize="14sp"
android:background="@drawable/btn_normal"
android:padding="6dp"
android:textColor="#666666"
android:layout_marginTop="6dp"/>
</LinearLayout>
<ImageView
android:id="@+id/emptyView"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_empty_page"
android:layout_gravity="center"/>
<ProgressBar
android:id="@+id/loadingView"
style="@android:style/Widget.ProgressBar"
android:indeterminateDrawable="@drawable/progress_medium_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
所用图片资源贴出:
双加载环drawable文件
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 在这里面定义两个相反方向旋转的圈 -->
<!-- 定义一个从0转到360度的圈 -->
<item>
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="@drawable/spinner_big_inner"/>
</item>
<!-- 定义一个从360转到0度的圈 -->
<item>
<rotate
android:fromDegrees="360"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:drawable="@drawable/spinner_big_outer"/>
</item>
</layer-list>
使用方式
- 单独使用
- 在抽象的基类中使用
如fragment的抽象基类,示例代码如下
public abstract class BaseFragment extends Fragment {
protected StateLayout rootView ;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//自定义界面显示View
rootView =new StateLayout(getContext());
//给自定义显示界面 增添第四种界面 即正常界面
rootView.setContentView(getFragmentLayouId());
ButterKnife.inject(this, rootView);
init();
return rootView;
}
protected abstract void init();
//抽象方法,正常界面根据子类不同情况去动态设置
protected abstract int getFragmentLayouId();
实现子类使用代码如下:
public class HomeFragment extends BaseFragment {
@InjectView(R.id.recycle_view)
RecyclerView recycleView;
private ArrayList<String> datas;
@Override
protected void init() {
//显示加载中
rootView.showLoadingView();
initDate();
}
//模拟数据
private void initDate() {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(1000);
datas = new ArrayList<>();
for (int i = 0; i < 100; i++) {
datas.add("我是数据" + i);
}
MyRecycleViewAdapter myRecycleViewAdapter = new MyRecycleViewAdapter(datas);
recycleView.setAdapter(myRecycleViewAdapter);
recycleView.addItemDecoration(new RecycleViewDivider(getContext(), LinearLayoutManager.HORIZONTAL));
recycleView.setLayoutManager(new LinearLayoutManager(getContext()));
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//加载完数据后显示正常界面,需要在UI线程更新
rootView.showContentView();
}
});
}
}).start();
}
//正常显示的界面
@Override
protected int getFragmentLayouId() {
return R.layout.fragment_main;
}
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.reset(this);
}
}