RecyclerView Adapter简单封装
Posted freeCodeSunny
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RecyclerView Adapter简单封装相关的知识,希望对你有一定的参考价值。
前言
今天是新年第一天,本来打算在上一年的最后一天写下来的,但是由于玩的时间长了一点,所以今天才写,算是在新的一年开一个好头,新年新气象嘛!
至于为什么要写这个文章呐!由于项目中以前都是用ListView实现的列表,很多东西都已经习惯化了,每次都是由的新的模块或者功能才使用RecyclerView,因此一直都没有完整的总结一遍,这次也是在一个新的项目中,准备完全采用RecyclerView来实现列表,因此初步的封装了一下。
为什么要封装呐?事实上,系统对该控件已经封装的很好了,直接拿过来用就行,使用方式也跟以前差不多,构造一个RecyclerView,再构造一个Adapter,当连续写了2个之后就不再想重复劳动了,因此对Adapter进行的简单的封装,
BaseAdapter
这里就大致罗列一下封装的过程,只是实现了初步的功能,后续的功能可以逐步添加,在最后会给出一个使用样例。
BaseAdapter
既然是对Adapter的简单封装,那第一步就是先来实现基类的Adapter,代码如下:
public class BaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder>
/**
* data source
*/
public List<T> dataList;
/**
* onClick onLongClick callback
*/
public onItemClickListener listener;
/**
* constructor view holder delegate
*/
public BaseDelegate delegate;
/**
* constructor
*
* @param dataList
* @param delegate
*/
public BaseAdapter(List<T> dataList, BaseDelegate delegate)
this(dataList, delegate, null);
/**
* constructor
*
* @param dataList
* @param delegate
* @param listener
*/
public BaseAdapter(List<T> dataList, BaseDelegate delegate, onItemClickListener listener)
checkData(dataList);
this.delegate = delegate;
this.listener = listener;
/**
* just is empty
*
* @param dataList
*/
private void checkData(List<T> dataList)
if (dataList == null)
dataList = Collections.emptyList();
this.dataList = dataList;
/**
* set onclick & onLongClick callback
*
* @param listener
*/
public void setOnItemClickListener(onItemClickListener listener)
this.listener = listener;
/**
* create view holder
*
* @param parent
* @param viewType
* @return
*/
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
return delegate.onCreateViewHolder(parent, viewType);
/**
* bind view holder
*
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position)
holder.onBindViewHolder(dataList.get(position));
if (listener != null && holder.enable())
holder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
listener.onClick(v, dataList.get(position));
);
holder.itemView.setOnLongClickListener(new View.OnLongClickListener()
@Override
public boolean onLongClick(View v)
return listener.onLongClick(v, dataList.get(position));
);
/**
* get item count
*
* @return
*/
@Override
public int getItemCount()
return dataList.size();
/**
* get item view type
*
* @param position
* @return
*/
@Override
public int getItemViewType(int position)
return delegate.getItemViewType(dataList.get(position));
1:这里首先是继承RecyclerView.Adapter,这里指定了一个BaseViewHolder,后续我们就来构建基类的ViewHolder。
2:传入需要操作的数据列表,这里加入了泛型,后续跟据实际使用的数据类进行使用。
3:由于RecyclerView不像ListView一样,默认实现了Item的点击事件,因此这里加入了点击事件的回调。
4:我们可以发现onCreateViewHolder,我们采用了代理来实现,等会我们会实现代理
5:在onBindViewHolder中,我们直接调用了Holder的bind过程,其次实现了点击事件。
BaseViewHolder
前面我们提到了统一实现一个基类ViewHolder,这里我们就看看BaseViewHolder怎么实现的。
public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder
/**
* TODO
* single view may be direct construction, eg: TextView view = new TextView(context);
*
* @param parent current no use, may be future use
* @param view
*/
public BaseViewHolder(ViewGroup parent, View view)
super(view);
findViews();
/**
* find all views
*/
public abstract void findViews();
/**
* bind view holder
*
* @param data
*/
public abstract void onBindViewHolder(T data);
/**
* holder click enable
*
* @return
*/
public boolean enable()
return true;
1:这里首先还是继承自RecyclerView.ViewHolder
2:在构造函数中加入了控件的查找
3:BaseViewHolder是一个抽象类,有一个抽象方法onBindViewHolder,主要是为什么了实现界面绑定功能
4:最后有一个enable函数,这里主要是item是否可以有点击效果
onItemClickListener
由于RecyclerView默认没有点击事件的回调,因此需要我们自定义来实现该效果。这里我们加入点击事件的回调:
public interface onItemClickListener<T>
void onClick(View v, T data);
boolean onLongClick(View v, T data);
1:功能能很简单,主要是实现了单击和长按的回调。也可以实现更改的回调
BaseDelegate
BaseDelegate也是一个抽象类,他主要是代理了Adapter中的create过程,代码如下:
public abstract class BaseDelegate<T>
/**
* crate view holder by view type
*
* @param parent
* @param viewType
* @return
*/
public abstract BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
/**
* get view type by data
*
* @param data
* @return
*/
public abstract int getItemViewType(T data);
/**
* get layout id by view type
*
* @param viewType
* @return
*/
public abstract int getLayoutId(int viewType);
/**
* get item view
*
* @param parent
* @param viewType
* @return
*/
public View getItemView(ViewGroup parent, int viewType)
return LayoutInflater.from(parent.getContext()).inflate(getLayoutId(viewType), parent, false);
1:这里主要是代理了onCreateViewHolder,返回一个具体的ViewHolder
2:还代理了getItemViewType,具体根据实现返回type类型
使用
上面的代码都很简单,简单的封装了整个使用过程,那在项目中又是怎么来使用的呐?是否使用变动更麻烦了?比如我们要实现如下效果:
界面布局
这里我们首先来创一个Activity,布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<include
android:id="@+id/my_toolbar"
layout="@layout/toolbar_title_layout"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/setting_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/my_toolbar">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
主要包含了一个标题与一个RecyclerView
界面代码
public class MainActivity extends AppCompatActivity
private RecyclerView settingInfo;
private List<ItemData> datas;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
initTitle();
initData();
initRecyclerView();
/**
* find views
*/
private void findViews()
settingInfo = (RecyclerView) findViewById(R.id.setting_info);
/**
* init title bar
*/
private void initTitle()
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
myToolbar.setNavigationIcon(android.support.v7.appcompat.R.drawable.abc_ic_ab_back_material);
myToolbar.setNavigationOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
setResult(RESULT_CANCELED);
finish();
);
ToolbarHelper.layoutTitleCenter(this, myToolbar, getString(R.string.title));
private void initData()
datas = new ArrayList<>(20);
datas.add(new ItemData(0, SettingDelegate.SELF_INFO));
datas.add(new ItemData(0, SettingDelegate.SEPARATE_TYPE));
for (int i = 0; i < 3; ++i)
datas.add(new ItemData(0, SettingDelegate.ARROW_TYPE, "我是箭头"));
datas.add(new ItemData(0, SettingDelegate.CHECK_TYPE, "选中我"));
datas.add(new ItemData(0, SettingDelegate.TOGGLE_TYPE, "开启"));
datas.add(new ItemData(0, SettingDelegate.SEPARATE_TYPE));
datas.add(new ItemData(0, SettingDelegate.LOGOUT_TYPE));
/**
* init
*/
private void initRecyclerView()
settingInfo.setHasFixedSize(true);
DividerItemDecoration decor = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
settingInfo.addItemDecoration(decor);
settingInfo.setLayoutManager(new LinearLayoutManager(this));
settingInfo.setAdapter(new BaseAdapter(datas, new SettingDelegate(), new onItemClickListener()
@Override
public void onClick(View v, Object data)
ArrowActivity.start(MainActivity.this);
@Override
public boolean onLongClick(View v, Object data)
return false;
));
1:查找了页面控件,并且设置了标题,构造了数据源
2:对RecyclerView设置了分割线,同时设置了布局管理器,这些都是基本功能,最后设置了Adapter,这里主要指定了数据源,同时设置了代理, 最后传入了点击事件的回调。
SettingDelegate
前面传入了SettingDelegate,这里我们看看SettingDelegate怎么实现的:
public class SettingDelegate extends BaseDelegate<ItemData>
public static final int SEPARATE_TYPE = 0;
public static final int SELF_INFO = 1;
public static final int ARROW_TYPE = 2;
public static final int CHECK_TYPE = 3;
public static final int TOGGLE_TYPE = 4;
public static final int LOGOUT_TYPE = 5;
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
switch (viewType)
case SEPARATE_TYPE:
return new SeparateViewHolder(parent, getItemView(parent, viewType));
case SELF_INFO:
return new SelfInfoViewHolder(parent, getItemView(parent, viewType));
case ARROW_TYPE:
return new ArrowViewHolder(parent, getItemView(parent, viewType));
case CHECK_TYPE:
return new CheckViewHolder(parent, getItemView(parent, viewType));
case TOGGLE_TYPE:
return new ToggleViewHolder(parent, getItemView(parent, viewType));
case LOGOUT_TYPE:
return new LogoutViewHolder(parent, getItemView(parent, viewType));
return null;
@Override
public int getItemViewType(ItemData data)
return data.holderType;
@Override
public int getLayoutId(int viewType)
switch (viewType)
case SEPARATE_TYPE:
return R.layout.view_holder_setting_separate;
case SELF_INFO:
return R.layout.view_holder_setting_self_info;
case ARROW_TYPE:
return R.layout.view_holder_setting_arrow;
case CHECK_TYPE:
return R.layout.view_holder_setting_check;
case TOGGLE_TYPE:
return R.layout.view_holder_setting_toggle;
case LOGOUT_TYPE:
return R.layout.view_holder_setting_logout;
return 0;
1:根据图片我们可以看到有多种类型,getItemViewType根据数据返回不同的type
2:onCreateViewHolder根据type返回每一种ViewHolder
3:这里我们指定了具体的数据类型ItemData,这个是随便构造的,真正项目中都是根据实际的数据来构造的
ItemData
这里的ItemData只是为了掩饰而构造的数据类型,代码如下:
public class ItemData
public int tag;
public int holderType;
public String itemDesc;
public Object data;
public ItemData(int tag, int holderType)
this.tag = tag;
this.holderType = holderType;
public ItemData(int tag, int holderType, String itemDesc)
this.tag = tag;
this.holderType = holderType;
this.itemDesc = itemDesc;
public ItemData(int tag, int holderType, Object data)
this.tag = tag;
this.holderType = holderType;
this.data = data;
SelfInfoViewHolder
这里有5种类型,我们就随机挑选一种来进行演示,这里我们选择了头像部分。代码如下:
public class SelfInfoViewHolder extends BaseViewHolder<ItemData>
private ImageView headView;
private TextView nameGender;
private TextView birthday;
/**
* @param parent
* @param view
*/
public SelfInfoViewHolder(ViewGroup parent, View view)
super(parent, view);
@Override
public void findViews()
headView = (ImageView) itemView.findViewById(R.id.self_info_head_view);
nameGender = (TextView) itemView.findViewById(R.id.self_name_gender);
birthday = (TextView) itemView.findViewById(R.id.birthday);
@Override
public void onBindViewHolder(ItemData data)
@Override
public boolean enable()
return false;
1:首先是继承自BaseViewHolder,指定了数据类型
2:查找了页面控件,保证在bind的时候使用。
3:onBindViewHolder进行数据与控件的绑定展示
4:enable指定了该条目不需要点击事件
总结
上面只是对Adapter的简单封装,不过大部分的功能已经够用了,很多人可能会在每一个ViewHolder构造的时候,传入Layout布局,这里采用Delegate来统一返回布局,将布局放在了一起,同时针对每一个页面可以实现直接的delegate,这样就将类型,处理与布局统一管理。方便改代码的时候查找代码。
代码
这里只是大致列出了其中一部分代码,为了方便使用最后给出代码地址:传送门
后记
本来开始写的时候还是新年第一天,写完的时候已经变成了新年第二天,要是昨天开始写,那岂不是就写了一年。
以上是关于RecyclerView Adapter简单封装的主要内容,如果未能解决你的问题,请参考以下文章
android RecyclerView adapter 封装
android RecyclerView adapter 封装
android RecyclerView adapter 封装
xml SectionedGridRecyclerViewAdapter:使用此类实现一个简单的分段网格`RecyclerView.Adapter`。