项目中有时候会经常遇到加载页面出错,加载页面没有数据,没有网络等等情况。这些情况需要一个特别的展示来告知用户,并且提供点击事件来重新加载等等情况。一般情况下我就直接在布局上面盖一层布局用来展示这种情况,如果只有一个页面或者极少页面需要这么做,也到简单。但是如果大量页面都需要,那我们的xml就难免会点的层级过多,不便于阅读。也有可能在preview的时候看不清我们真正需要展示的页面结构等等,基于此,本着大家一起学习的态度,我写了一个简单的代码用以封装这种情形。
其中的原理可以先阅读鸿洋大神的此篇博客 Android 源码解析 之 setContentView。
private FrameLayout mFrameLayout; //此处即为android中我们setContentView时根布局的父布局
private View mDefaultView; //这是我们加载页面出错,或者没有网络时的默认布局
private View mContentView;//这是我们自己真正的业务逻辑的布局
@Override
public void setContentView(@LayoutRes int layoutResID) {
mFrameLayout = (FrameLayout) findViewById(android.R.id.content);
mDefaultView = LayoutInflater.from(activity).inflate(R.layout.default_layout, mFrameLayout, false);//这个defaul_layout是统一的错误页面展示布局
mContentView = LayoutInflater.from(activity).inflate(layoutResID, mFrameLayout, false);//这个layoutResId就是我们需要的业务逻辑布局了
//将出错页面和逻辑页面分别加载到mFramLayout中去,并隐藏出错页面
mFrameLayout.addView(mContentView);
mFrameLayout.addView(mDefaultView);
mDefaultView.setVisibility(View.GONE);
}
/**
*
**
/
protected void showDefaultView() {
mDefaultView.setVisibility(View.VISIBLE);
mContentView.setVisibility(View.GONE);
}
protected void hideDefaultView() {
mDefaultView.setVisibility(View.GONE);
mContentView.setVisibility(View.VISIBLE);
}
R.layout.default_layout的布局文件如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/default_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_luncher" />
<TextView
android:id="@+id/default_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这个地方空空如也" />
</LinearLayout>
那这个默认布局,我如果不一样了?比如网络加载出错的图片,和没有获取到内容的图片等等,我该如何修改呢?
private ImageView defaultImage;
private TextView defaultText;
/**
* @param drawableResID 需要更换的图标
* @param text 需要更换的问题
* @param listener 图标的点击事件
*
* 你可以只放一个drawableResID,那么此处的textView将会被隐藏,你可以选择将image和文字切成一张图,这样就简单多了。比较懒的方法
*/
protected void initDefaultView(@DrawableRes int drawableResID, String text, View.OnClickListener listener) {
defaultImage = (ImageView) findViewById(R.id.default_image_view);
defaultText = (TextView) findViewById(R.id.default_text_view);
if (drawableResID <= 0) {
defaultImage.setVisibility(View.GONE);
} else {
defaultImage.setVisibility(View.VISIBLE);
defaultImage.setImageResource(drawableResID);
}
if (TextUtils.isEmpty(text)) {
defaultText.setVisibility(View.GONE);
} else {
defaultText.setVisibility(View.VISIBLE);
defaultText.setText(text);
}
if (listener != null) {
mDefaultView.setOnClickListener(listener);
}
}
如果项目中有的页面出错页面比较简单,有的比较复杂,或者布局样式根本就和默认的布局已经千差万别了,咋办?
那我们将上面的代码改一下,我们先定义一个方法,默认返回空
protected View useCustomLayout() {
return null;
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
mFrameLayout = (FrameLayout) findViewById(android.R.id.content);
//此处我们先判断是否重写了useCustomLayout这个方法,如果重写了,那么就将defaultView赋值为重写返回的view即可
if (useCustomLayout() == null) {
mDefaultView = LayoutInflater.from(activity).inflate(R.layout.default_layout, mFrameLayout, false);
} else {
mDefaultView = useCustomLayout();
}
mContentView = LayoutInflater.from(activity).inflate(layoutResID, mFrameLayout, false);
mFrameLayout.addView(mDefaultView);
mFrameLayout.addView(mContentView);
mDefaultView.setVisibility(View.GONE);
}
完整代码如下
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import minihou.net.library.R;
/**
* Created by monking-macbook
* on 2017/6/13
* in MiniHouBaseCore
* description: use a dialog to introduce this class
*/
public class MiniHouBaseActivity extends AppCompatActivity {
protected Activity activity;
private FrameLayout mFrameLayout;
private View mDefaultView;
private View mContentView;
private ImageView defaultImage;
private TextView defaultText;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
mFrameLayout = (FrameLayout) findViewById(android.R.id.content);
if (useCustomLayout() == null) {
mDefaultView = LayoutInflater.from(activity).inflate(R.layout.default_layout, mFrameLayout, false);
} else {
mDefaultView = useCustomLayout();
}
mContentView = LayoutInflater.from(activity).inflate(layoutResID, mFrameLayout, false);
mFrameLayout.addView(mDefaultView);
mFrameLayout.addView(mContentView);
mDefaultView.setVisibility(View.GONE);
}
protected View useCustomLayout() {
return null;
}
/**
* @param drawableResID 需要更换的图标
* @param text 需要更换的问题
* @param listener 图标的点击事件
*/
protected void initDefaultView(@DrawableRes int drawableResID, String text, View.OnClickListener listener) {
if (useCustomLayout() != null) {
return;
}
defaultImage = (ImageView) findViewById(R.id.default_image_view);
defaultText = (TextView) findViewById(R.id.default_text_view);
if (drawableResID <= 0) {
defaultImage.setVisibility(View.GONE);
} else {
defaultImage.setVisibility(View.VISIBLE);
defaultImage.setImageResource(drawableResID);
}
if (TextUtils.isEmpty(text)) {
defaultText.setVisibility(View.GONE);
} else {
defaultText.setVisibility(View.VISIBLE);
defaultText.setText(text);
}
if (listener != null) {
defaultImage.setOnClickListener(listener);
}
}
/**
* 如果加载出错show出这个默认布局并隐藏我们的业务逻辑布局
*/
protected void showDefaultView() {
mDefaultView.setVisibility(View.VISIBLE);
mContentView.setVisibility(View.GONE);
}
/**
* 如果没有出错,就展示我们的业务逻辑布局,并隐藏出错的布局。
*/
protected void hideDefaultView() {
mDefaultView.setVisibility(View.GONE);
mContentView.setVisibility(View.VISIBLE);
}
}
使用方法
首先创建Activity继承上述Activity,然后。。。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//千万注意得先调用setContentView
if(true){//加载数据没出错,页面数据不为空等等
hideDefaultView();
}else{
showDefaultView();
}
}
如果需要更改图标和文字,添加点击事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDefaultView(R.drawable.new_icon, "此处空空如也", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击页面重试", Toast.LENGTH_SHORT).show();
}
});
}
如果需要自己定义布局
@Override
protected View useCustomLayout() {
View view=LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_layout, null);
return view;
}
好了,有需要的同学可以去试试哦,如果有改进可以在下面留言给我。
网友评论