一、背景
很久很久以前简单封装过一次RecyclerView,后来一直开发TV端,列表的需求花样不是很多,主要是解决TV端各种兼容问题,也没怎么琢磨这个美丽的控件了,现在打算重新整理一下,其实网上已经有很多优秀的开源项目了,涵盖功能多,但是就因为功能太多,用起来反而有一些不方便的地方,例如用在TV上或者别的什么地方,有的地方得根据需求和兼容问题作出修改,这样改起来就麻烦了,看的头皮发麻呀,而且很多功能用不到,用第三方库时,你们是不是也是多一个功能都不想要,所以还是自己搞一下,可以方便的扩展和修改,最终效果:
先说下之前的,RecyclerView下拉刷新很简单,直接通过其外层包裹的SwipeRefreshLayout提供的接口即可实现,然后我就自然而然的像自定义其它控件一样把这两个控件给自定义成了一个组合控件,使用时如下:
<com.wasu.tvfc.widget.ARecycleView
android:id="@+id/ac_recycler"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:EmptyView="@layout/empty_view"
app:layout_moreProgress="@layout/view_more_progress" />
mAdapter = new WechatAdapter(mContext, mList);
recyclerview.setLayoutManager(new LinearLayoutManager(mContext,LinearLayoutM
recyclerview.setAdapter(mAdapter);
recyclerview.setOnLoadMoreListener(new ARecycleView.OnLoadMoreListener() {
@Override
public void loadMore() {
mPresenter.getMoreWechatData();
}
});
recyclerview.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
@Override
public void onRefresh() {
mPresenter.getWechatData();
}
});
之前感觉这样用起来很方便了,但是随着时代的进步,祖国的发展,人民生活水平不断提高,房价也越来越贵了,想生活的简单点的我,越来越觉得之前那种写法用起来不是很舒服,因此对自己提出了几点疑问:
Q:为何要把 SwipeRefreshLayout 和 RecyclerView 封装到一起?
A:当时需求不是很多,在布局的写法也基本一样,所以这种一堆控件不如写成一个组合控件用的方便;
Q:这其实是一种惯性思维,为何要把数据为空的展示逻辑也封装到这个组合控件里了?
A:之前用 ListView 时也经常有列表为空的展示需求,现在自定义 RecyclerVIew 就干脆把这个功能也一起封装到这个组合控件里,让其功能尽量完善;
Q:这样一来其它不包含列表的页面数据为空时如果也要显示一个特殊页,就得再写一套空展示逻辑,这就和 RecyclerView 里的重复了,这不成了形而上学了,现在我想要一个纯净的写法,还要能实现上拉加载更多和下拉刷新,就像这样:
<android.support.constraint.ConstraintLayout 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"
tools:context=".activity.ListMoreActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.constraint.ConstraintLayout>
总结:
1.别的控件为了使用方便可以自定义成一个组合控件,但是 SwipeRefreshLayout 和 RecyclerView 定义到一起感觉有点不爽;
2.empty 页面直接定义到 RecyclerView 里其实不是一种完美的做法,会有很多局限,例如其它没有用到 RecyclerView 的页面如果也要在无数据时展示 empty 页面,这时又得重新搞一套逻辑,所以这种特殊页面应该单独搞一个模块,本文暂不涉及;
3.要在布局里不改变原生写法的情况下实现加载更多和下拉刷新逻辑。
二.方案
既然不能在封装 RecyclerView 和 SwipeRefreshLayout 上做文章了,那么就只好去找 Adapter 看看了,思索了许久终于想到了两个方案;(什么?你说我是看了github 上的开源项目才想到的?就你知道的多)
2.1方案一:Adapter 和布局都以原生的方式来写,然后把原生的 Adapter 装饰一把,增加上拉加载更多的逻辑,加载判断等逻辑放到一个单独工具类里;
思路如下:
1.布局及 adapter 都以原生的方式来写;
2.装饰 adapter 的功能,通过 itemType 区分使用哪种 ViewHolder,从而区分展示内容布局,加载更多布局什么的;
3.再用一个单独的工具类来处理加载更多的监听判断逻辑;
Activity的xml:
<android.support.constraint.ConstraintLayout 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"
tools:context=".activity.ListMoreActivity">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.constraint.ConstraintLayout>
adapter:
public class ListMoreAdapter extends RecyclerView.Adapter<ListMoreAdapter.MyViewHolder> {
private List<String> mList;
public ListMoreAdapter(List<String> list) {
this.mList = list;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false));
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.tv.setText(mList.get(position));
}
@Override
public int getItemCount() {
return mList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView tv;
private MyViewHolder(View itemView) {
super(itemView);
tv = itemView.findViewById(R.id.textview);
}
}
}
Activity里使用:
public class ListMoreActivity extends BaseActivity {
private static Handler mHandler = new Handler();
private ALoadMoreAdapterWrapper aLoadMoreAdapterWrapper;
@Override
protected void init() {
initData();
}
private void initData() {
ListMoreAdapter listMoreAdapter = new ListMoreAdapter(mDatas);
aLoadMoreAd