我们经常会碰见 正在加载中,加载出错, “暂无商品”等一系列的相似的布局,因为我们有很多请求网络数据的页面,我们不可能每一个页面都写几个“正在加载中”等布局吧,这时候将这些状态的布局封装在一起就很有必要了。我们可以将这些封装为一个自定布局,然后每次操作该自定义类的方法就行了。
首先一般来说,从服务器拉去数据之前都是“正在加载”页面, 加载成功之后“正在加载”页面消失,展示数据;如果加载失败,就展示“加载出错”页面,同样的“z正在加载”消失; 同理 数据为null的话,也是这样。如下图所示:
其实这只是一种代码设计模式,有这种思想就行,实现起来千变万化的。
总体思想就是:自定义FrameLayout ,然后将这FrameLayout中有三个子view,分别是:展示数据的view,加载失败的view, 正在加载的view,数据为null的view; 其实展示数据的view是一直VISIBLE的,切记:其他三个view都要设置为match_parent,然后父布局都要设置color ;
比如数据为null的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@android:color/white">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="暂无数据!"/>
</LinearLayout>
父布局是match——parent 然后也设置了颜色;
在声明SynExceptionLayout 的XML中,要如下声明:
<?xml version="1.0" encoding="utf-8"?>
<com.app.test.testerrorproject.SynExceptionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.app.test.testerrorproject.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="有数据"
android:textSize="30sp"
android:textColor="@color/colorAccent" />
</LinearLayout>
</com.app.test.testerrorproject.SynExceptionLayout>
可以看到SynExceptionLayout 是在最外层的,而添加的第一个view就是LinearLayout。
看下源码吧
package com.app.test.testerrorproject;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by ${liumengqiang} on 2017/7/17.
*/
public class SynExceptionLayout extends FrameLayout {
/**
* 一般的执行顺序是:网络访问前 loadShow(), 然后加载成功之后,successShow();
* 如果加载出错的话,errorShow();
* 如果加载数据为null的话,emptyShow();
* 一般来说使用emptyShow(int res),即自定义布局
*/
private LinearLayout emptyLinearLayout;//数据位null时,应该显示的布局
private LinearLayout errorLinearLayout;//数据加载出错时,应该显示的布局
private LinearLayout loadLinearLayout;//正在加载时,应该显示的布局
public static final int EMPTY_INT = 0;//回调标记:数据为null
public static final int ERROR_INT = 1;//回调标记:数据出错
public static final int LOAD_INT = 2;//回调标记:数据正在加载
private OnSynExceptionListaner onSynExceptionListaner;
public OnSynExceptionListaner getOnSynExceptionListaner() {
return onSynExceptionListaner;
}
public void setOnSynExceptionListaner(OnSynExceptionListaner onSynExceptionListaner) {
this.onSynExceptionListaner = onSynExceptionListaner;
}
public SynExceptionLayout(Context context) {
super(context);
}
public SynExceptionLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SynExceptionLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 加载为null
*/
public void emptyShow(){//默认加载
empty(R.layout.empty_layout);
}
public void emptyShow(int res){//指定加载布局
empty(res);
}
public void empty(int res){
if(emptyLinearLayout == null){
emptyLinearLayout = (LinearLayout) LayoutInflater.from(getContext())
.inflate(res, this,false);
emptyLinearLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSynExceptionListaner.onSynxceptionListener(EMPTY_INT);
}
});
}
if(errorLinearLayout == null){
errorLinearLayout.setVisibility(View.GONE);
}
if(loadLinearLayout == null){
loadLinearLayout.setVisibility(View.GONE);
}
/**
* indexOfChild(View view) 方法返回该view在frameLayout中的位置索引
* 不在里面时,返回 -1;
*
* addView(View view) 将view添加到frameLayout中
*/
if(indexOfChild(emptyLinearLayout) == -1){
addView(emptyLinearLayout);
emptyLinearLayout.setVisibility(View.VISIBLE);
}else{
emptyLinearLayout.setVisibility(View.VISIBLE);
}
}
/**
* 加载出错
*/
public void errorShow(){
error(R.layout.error_layout);
}
public void errorShow(int res){
error(res);
}
private void error(int res){
if(errorLinearLayout == null){
errorLinearLayout = (LinearLayout) LayoutInflater.from(getContext())
.inflate(res, this,false);
errorLinearLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSynExceptionListaner.onSynxceptionListener(ERROR_INT);
}
});
}
if(loadLinearLayout != null){
loadLinearLayout.setVisibility(View.GONE);
}
if(emptyLinearLayout != null){
emptyLinearLayout.setVisibility(View.GONE);
}
if(indexOfChild(errorLinearLayout) == -1){
addView(errorLinearLayout);
errorLinearLayout.setVisibility(VISIBLE);
}else{
errorLinearLayout.setVisibility(VISIBLE);
}
}
/**
* 正在加载
*/
public void loadShow(){
load(R.layout.load_layout);
}
public void loadShow(int res){
load(res);
}
private void load(int res){
if(loadLinearLayout == null){
loadLinearLayout = (LinearLayout) LayoutInflater.from(getContext())
.inflate(res, this, false);
loadLinearLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSynExceptionListaner.onSynxceptionListener(LOAD_INT);
}
});
}
if(errorLinearLayout != null){
errorLinearLayout.setVisibility(View.GONE);
}
if(emptyLinearLayout != null){
emptyLinearLayout.setVisibility(View.GONE);
}
if(indexOfChild(loadLinearLayout) == -1){
addView(loadLinearLayout);
loadLinearLayout.setVisibility(View.VISIBLE);
}else{
loadLinearLayout.setVisibility(View.VISIBLE);
}
}
/**
*成功时,将三个布局都设置为GONE
*/
public void successShow(){
if(emptyLinearLayout != null){
emptyLinearLayout.setVisibility(View.GONE);
}
if(errorLinearLayout != null){
errorLinearLayout.setVisibility(View.GONE);
}
if(loadLinearLayout != null){
loadLinearLayout.setVisibility(View.GONE);
}
}
/**
* 回调接口
*/
public interface OnSynExceptionListaner{
void onSynxceptionListener(int flug);
}
}
附上操作SynExceptionLayout 的demo 想使用这种封装的可以参考下