RecyclerView Adapter简单封装
2017-01-02 01:17
351 查看
前言
今天是新年第一天,本来打算在上一年的最后一天写下来的,但是由于玩的时间长了一点,所以今天才写,算是在新的一年开一个好头,新年新气象嘛!至于为什么要写这个文章呐!由于项目中以前都是用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的简单封装
- 简单封装RecyclerView的Adapter
- RecyclerViewAdapter的简单封装
- RecyclerView.Adapter 的简单封装
- 封装RecyclerViewAdapter实现RecyclerView下拉刷新上拉加载更多
- RecyclerView.Adapter的优化与封装
- android RecycleView Adapter简单封装
- Android 封装RecyclerView的Adapter
- RecyclerView中Adapter和ViewHolder的封装
- RecyclerView Adapter 封装
- RecyclerView封装Adapter之添加头部和底部视图
- android RecycleView Adapter简单封装
- RecyclerView 使用的简单封装
- RecyclerView.Adapter的封装之路
- 简单的封装BaseRecycleviewAdapter
- RecyclerView通用适配器Adapter,对Adapter的封装
- 超级简单RecycleViewAdapter的封装-支持多视图,多点击回调
- 超级简单RecycleViewAdapter的封装-支持多视图,多点击回调
- 简单好用的上拉加载下拉刷新 BaseRecyclerViewAdapterHelper
- RecyclerView 的简单封装