Android通用的EmptyLayout-展示不用状态的界面
2016-08-31 16:45
423 查看
转载请标明出处: http://www.weyye.me/detail/empty-layout/
本文出自:【Wey Ye的博客】
在数据加载失败后,添加一个Button让用户可以选择重新加载数据。
你肯定会说,findviewbyId找到这个button,给它设置点击事件,一个两个可以接受,但是,界面多了呢? 那你说了那么多,有没有好的解决办法呢? 当然有 而且是几行代码搞定的
为了灵活性,我自定义属性来添加所需要的布局,
然后我们以此找到这些布局,并且添加进去
简单说下几个变量的作用
好了,首先我们找到布局,然后添加进去,如果没有,添加默认的布局。至此,布局已经完成,那怎么控制呢?我们想要的是什么效果呢?
在数据正在加载的时候调用loading方法,显示正在加载中的文本。
在数据加载成,隐藏该view。
在数据加载失败,显示加载失败的文本,并提供一个按钮去刷新数据。
ok,我们按照这个条目一个个的来实现,首先是loading。
首先判断下我们要绑定view是不是为空,不为空则隐藏它,隐藏其他布局,然后展示loadingview
那加载失败了呢?同样简单!
这个同上
继续看看加载成功的方法,这个更简单啦。
至此,我们整个效果就完成了,在加载数据的时候调用
控件倒是完成了,我们还不知道mBindView怎么来的,其实也很简单。我们在代码中需要调用bindView(View view)方法来指定。
那么问题来了,我加载失败后,按钮的点击事件怎么做呢?有人会说用反射,这样既省了代码行数,看着又舒服,但是这样是有个问题存在的,大家都知道,一个项目的上线,都会进行混淆代码的,为了就是防止他人剽窃我们的劳动成果,可是混淆过后哪些class全部变成a,b,c ,这样如果用反射的话就会导致点击事件失效,因为找不到这个类,所以,我们还是老老实实的用onclick事件吧
这样,一个简单的
先看
在看看Activity中怎么调用
首页我们找到控件,然后给
——————————-Demo下载地址↓——————————-
学习理解并整理下来的笔记。
希望大家能够指点或提出宝贵意见,谢谢!一起学习。
转载请注明出处:http://www.weyye.me/detail/empty-layout/
个人站点:http://weyye.me
本文出自:【Wey Ye的博客】
前言
在做项目的时候,经常会遇到列表数据为空的时候展示的空布局,如果你用的是ListView,目测会经常使用
ListView的一个方法
setEmptyView,如果你用的是
RecyclerView,你也许会用自定义View来实现,但是,这些方法虽然使用起来简单,但是如果你提供一个复杂的布局,例如:
在数据加载失败后,添加一个Button让用户可以选择重新加载数据。
你肯定会说,findviewbyId找到这个button,给它设置点击事件,一个两个可以接受,但是,界面多了呢? 那你说了那么多,有没有好的解决办法呢? 当然有 而且是几行代码搞定的
自定义View
接下来就是重头戏 开始编码了 ,首先我们需要继承FrameLayout来实现这样的布局
public class EmptyLayout extends FrameLayout { public EmptyLayout(Context context) { this(context, null); } public EmptyLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public EmptyLayout(Context context, AttributeSet attrs, int defStyleAttr) { } }
为了灵活性,我自定义属性来添加所需要的布局,
values下面新建
attrs.xml
<resources> <declare-styleable name="EmptyLayout"> <attr name="elEmptyLayout" format="reference"/> <attr name="elErrorLayout" format="reference"/> <attr name="elLoadingLayout" format="reference"/> </declare-styleable> </resources>
然后我们以此找到这些布局,并且添加进去
public class EmptyLayout extends FrameLayout { private Context mContext; private View mEmptyView; private View mBindView; private View mErrorView; private Button mBtnReset; private View mLoadingView; private View loadingView; private TextView mEmptyText; private TextView tvLoadingText; public EmptyLayout(Context context) { this(context, null); } public EmptyLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public EmptyLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext=context; LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); //居中 params.gravity = Gravity.CENTER; TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.EmptyLayout, 0, 0); //数据为空时的布局 int emptyLayout = ta.getResourceId(R.styleable.EmptyLayout_elEmptyLayout, R.layout.layout_empty); mEmptyView = View.inflate(context, emptyLayout, null); mEmptyText =(TextView)mEmptyView.findViewById(R.id.tvEmptyText); addView(mEmptyView,params); //加载中的布局 int loadingLayout = ta.getResourceId(R.styleable.EmptyLayout_elLoadingLayout, R.layout.layout_loading); mLoadingView = View.inflate(context, loadingLayout, null); tvLoadingText =(TextView)mLoadingView.findViewById(R.id.tvLoadingText); addView(mLoadingView,params); //错误时的布局 int errorLayout = ta.getResourceId(R.styleable.EmptyLayout_elErrorLayout, R.layout.layout_error); mErrorView = View.inflate(context, errorLayout, null); mBtnReset =(Button)mErrorView.findViewById(R.id.btnReset); addView(mErrorView, params); //全部隐藏 setGone(); } /** * 全部隐藏 */ private void setGone() { mEmptyView.setVisibility(View.GONE); mErrorView.setVisibility(View.GONE); mLoadingView.setVisibility(View.GONE); } }
简单说下几个变量的作用
mEmptyView表示数据为空的时候展示给用户
mEmptyText数据为空提示的文字
mErrorView加载错误展示给用户
mBtnReset加载错误重新加载的按钮
mLoadingView加载中展示给用户
tvLoadingText加载中提示的文字
mBindView我们要绑定的view
好了,首先我们找到布局,然后添加进去,如果没有,添加默认的布局。至此,布局已经完成,那怎么控制呢?我们想要的是什么效果呢?
在数据正在加载的时候调用loading方法,显示正在加载中的文本。
在数据加载成,隐藏该view。
在数据加载失败,显示加载失败的文本,并提供一个按钮去刷新数据。
ok,我们按照这个条目一个个的来实现,首先是loading。
public void showLoading(String text) { if (mBindView != null) mBindView.setVisibility(View.GONE); if (!TextUtils.isEmpty(text)) tvLoadingText.setText(text); setGone(); mLoadingView.setVisibility(View.VISIBLE); } public void showLoading() { showLoading(null); }
首先判断下我们要绑定view是不是为空,不为空则隐藏它,隐藏其他布局,然后展示loadingview
那加载失败了呢?同样简单!
public void showError() { showError(null); } public void showError(String text) { if (mBindView != null) mBindView.setVisibility(View.GONE); if (!TextUtils.isEmpty(text)) mBtnReset.setText(text); setGone(); mErrorView.setVisibility(View.VISIBLE); }
这个同上
继续看看加载成功的方法,这个更简单啦。
public void showSuccess() { if (mBindView != null) mBindView.setVisibility(View.VISIBLE); setGone(); }
至此,我们整个效果就完成了,在加载数据的时候调用
showLoading方法来显示加载中的文本,加载失败后,调用
showError来显示加载失败的文本和刷新的按钮,在加载成功后直接隐藏控件
控件倒是完成了,我们还不知道mBindView怎么来的,其实也很简单。我们在代码中需要调用bindView(View view)方法来指定。
public void bindView(View view) { mBindView = view; }
那么问题来了,我加载失败后,按钮的点击事件怎么做呢?有人会说用反射,这样既省了代码行数,看着又舒服,但是这样是有个问题存在的,大家都知道,一个项目的上线,都会进行混淆代码的,为了就是防止他人剽窃我们的劳动成果,可是混淆过后哪些class全部变成a,b,c ,这样如果用反射的话就会导致点击事件失效,因为找不到这个类,所以,我们还是老老实实的用onclick事件吧
public void setOnButtonClick(OnClickListener listener) { mBtnReset.setOnClickListener(listener); }
这样,一个简单的
EmptyLayout就诞生了,接下来我们来看看怎么使用
先看
xml布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="me.weyye.emptylayout.MainActivity"> <me.weyye.library.EmptyLayout xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/emptyLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:elEmptyLayout="@layout/layout_empty" app:elErrorLayout="@layout/layout_error" app:elLoadingLayout="@layout/layout_loading"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v7.widget.RecyclerView> </me.weyye.library.EmptyLayout> </RelativeLayout>
在看看Activity中怎么调用
public class MainActivity extends Activity { private EmptyLayout emptyLayout; private RecyclerView recyclerView; private List<String> list = new ArrayList<>(); private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); loadData(); } private Handler mHandler = new Handler(); private void initView() { emptyLayout = (EmptyLayout) findViewById(R.id.emptyLayout); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); recyclerView.setAdapter(adapter = new MyAdapter(list)); //绑定 emptyLayout.bindView(recyclerView); emptyLayout.setOnButtonClick(new View.OnClickListener() { @Override public void onClick(View v) { //重新加载数据 loadData(); } }); } private void loadData() { //模拟加载数据 emptyLayout.showLoading("正在加载,请稍后"); mHandler.postDelayed(new Runnable() { @Override public void run() { Random r = new Random(); int res = r.nextInt(10); if (res % 2 == 0) { // 失败 emptyLayout.showError("加载失败,点击重新加载"); // 显示失败 } else { // 成功 emptyLayout.showSuccess(); for (int i = 0; i < 15; i++) { list.add("测试" + i); } adapter.notifyDataSetChanged(); } } }, 3000); } }
首页我们找到控件,然后给
recyclerView设置
adapter,然后我们调用
emptyLayout.bindView(recyclerView);来设置要绑定的
view,当然这里是recyclerView,接下来,通过
emptyLayout.setOnButtonClick()来设置重新加载的时候执行哪个方法,在
loadData()中延迟3秒获取数据,数据成功失败都是随机的,当失败的时候会调用
emptyLayout.showError(),成功就调用emptyLayout.showSuccess();就这么简单,来看看运行效果
效果展示
——————————-Demo下载地址↓——————————-
学习理解并整理下来的笔记。
希望大家能够指点或提出宝贵意见,谢谢!一起学习。
转载请注明出处:http://www.weyye.me/detail/empty-layout/
个人站点:http://weyye.me
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories