RecyclerView-Adapter系列简述(第1篇)
序
从这篇文章文章开始将会连载几篇文章简单描述下最近抽空针对RecyclerView
的Adapter
做的一个扩展库。系列文章是对扩展库逐步进行扩展的,有一定的先后关系,所以阅读的话还是按照这个顺序比较好。
这篇先不开始描述怎么去扩展,先说一下这个扩展库将拥有什么样的功能以及如何使用,也就是告诉读者这些功能是不是符合口味,能不能吸引再往下读。
该库github地址:
https://github.com/yangxiaoweihn/RecyclerViewAdapter
该系列内容已经完结,其他部分可以点击下列阅读:
RecyclerView-为Adapter添加头部、尾部及事件响应(第2篇)
RecyclerView-数据域的操作方法(第3篇)
RecyclerView-为Adapter增加滑动菜单支持(第4篇)
RecyclerView-为Adapter增加粘性头部支持(第5篇)
本篇主要描述以下几方面内容:
- 扩展库如何在项目中使用
- 扩展库具有的功能
- 贴图看看效果
- 扩展库的api使用说明
扩展库的使用
该库已经打包上传到了maven
、jcenter
仓库,使用Android Studio
开发的同学肯定都知道怎么从仓库引入库的。
特殊注意:另外,这系列文章是针对源码版本2.0描述的
compile 'ws.dyt.view:recyclerview-adapter-hf:2.0'
具有的功能
- 可以添加、删除任意数量的头部、尾部(就像ListView那样)
- 可以添加系统头部、尾部(数量和使用上做了限制,在使用上尽量不要去使用这部分),具体说明将会在之后的文章中进行阐述。
- 可以针对不同的item添加滑动菜单(目前只支持左滑、右滑),并且菜单定制性高
- 支持粘性视图,同时支持滑动菜单
效果图
在能让读者有足够的好奇心读以下的文章前,先贴几张效果图,拿效果图最能说明该库拥有的功能。
1.png 2.png 3.png 4.png 5.png 6.png 7.png好了,效果图已经贴完,如果觉得这些功能不够吸引的话,同学就可以止步了,因为只有得系列文章主要是为了阐述以上功能的开发过程及思路。
api使用说明
首先要说明一点:该api的使用与系统原生提供的有区别,不要思维定式。简单说起来就是使用更简单,大概姿势如下:
1. 构造(构造方法)
2. 数据绑定
3. 多类型支持(设置布局,如果需要的话)
4. 事件
5. 添加头部尾部控件
6. 横跨列处理
7. 添加菜单
8. 添加粘性头部
该库主要实现了两个具有一定功能的Adapter
,命名为SuperAdapter
、SuperPinnedAdapter
。从实现上来讲,SuperPinnedAdapter
间接继承自SuperAdapter
,所以功能上就不言而喻了。
SuperAdapter
具有添加头部尾部、以及滑动菜单功能,而SuperPinnedAdapter
在此基础上增加了粘性视图的支持。
通过构造方法进行初始化(具体的参数说明请看注释)
/**
* 调用该构造方法时需要调用 {@link #getItemViewLayout(int)} 设置item布局
* @param context
* @param datas
*/
public SuperAdapter(Context context, List<T> datas) {
super(context, datas);
}
/**
* 调用该构造方法时默认数据项都采用 itemLayoutResId 布局,同样可以调用 {@link #getItemViewLayout(int)} 重新设置item布局
* @param context
* @param datas
* @param itemLayoutResId
*/
public SuperAdapter(Context context, List<T> datas, @LayoutRes int itemLayoutResId) {
this(context, datas);
}
以上两个构造方法最大的区别是:用第一种方法构造后需要调用getItemViewLayout()
设置item的布局。用后一种的话已经设置了item布局,不过这种方式是所有的item布局都是一样的。
数据绑定
数据的绑定在原生里是onBindViewHolder()
,而在这里,将该方法进行了屏蔽,而是用convert()
方法(使用上与onBindViewHolder()
一致,但是也更简单),可以简单的将他俩看成是对等的关系,但是事实上不是这样的,具体的我将会在后续的文章中进行具体描述。
/**
* 绑定数据
* @param holder
* @param position 数据域从0开始,已经除去头部
*/
abstract
public void convert(BaseViewHolder holder, int position);
该方法的第一个参数该库做了进一步封装,具体来说就是整个库里BaseViewHolder
类无法被扩展,所有常用的操作方法已经在该类中进行了封装(后续版本在决定是否可以允许该类扩展),BaseViewHolder
的功能将会在后面的文章进行描述。BaseViewHolder
的链条操作:
//只是一个例子而已,旨在说明链条操作,不必注意实体类是什么
CourseResult.Course e = getItem(position).data;
holder.
setText(R.id.tv_name, e.name).
setText(R.id.tv_length, e.length);
多item支持
通过构造方法已经知道,用构造方法是没有办法设置Adapter
的多item样式支持的。那么在该库中,通过以下方法进行设置:
/**
* 提供item对应的布局
*/
public int getItemViewLayout(int position) {}
事件
网上一大片文章都在讲RecyclerView
怎么设置item的点击事件云云,事实上确实很简单,RecyclerView
暴露的方法就那么几个,所以在这里事件是怎么加上去的也将在后续的文章中阐述,这里只需要知道该库一定也提供了设置事件监听的方法。
对item的点击事件支持以下两种:
/**
* 点击事件
*/
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
/**
* 长按事件
*/
public interface OnItemLongClickListener {
void onItemLongClick(View itemView, int position);
}
设置监听器:
//设置点击事件
adapter.setOnItemClickListener(new SuperAdapter.OnItemClickListener() {
@Override
public void onItemClick(View itemView, int position) {
}
});
//设置长按事件
adapter.setOnItemLongClickListener(new SuperAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(View itemView, int position) {
}
});
添加头部、尾部控件
原生RecyclerView
并没有提供像ListView
中那样可以随意添加header和footer的api,但是在实际的场景中我们确实需要这样的功能,那么该库也一定提供了这样的方法。
首先需要简单说一下SuperAdapter
数据域的构成:
{
item_sys_header - item_header -
item_data -
item_footer - item_sys_footer
}
从上面的结构中可以看到,大体分为3中(header部分、数据部分、footer部分),细分的话,头部又分为系统header部分(item_sys_header)和用户header部分(item_header),footer部分分为系统footer部分(item_footer)和用户footer部分(item_sys_footer)。
我为什么要这么划分呢,在实现上是有一些考虑的,头部和尾部不要去污染数据部分(分离),这样在扩展上更好一些。一般在使用时系统header和系统footer可以忽略,加这两个的用途也是为了扩展用,比如在我的另外一个上拉加载库中就用了系统footer。
主要提供了一下几个api:
final
public void addHeaderView(View view);
final
public void addHeaderView(View view, boolean changeAllVisibleItems);
final
public void removeHeaderView(View view);
final
public void removeHeaderView(View view, boolean changeAllVisibleItems);
final
public void addFooterView(View view);
final
public void addFooterView(View view, boolean changeAllVisibleItems);
final
public void removeFooterView(View view);
final
public void removeFooterView(View view, boolean changeAllVisibleItems);
其中changeAllVisibleItems表示是否只刷新可见区域(为true时),否则只刷新当前发生变化的item,默认为false
横跨列的api
在RecyclerView
的布局管理器是GridLayoutManager
或者StaggeredGridLayoutManager
时,有些item需要横跨所有列,这种情况下我们也提供了以下api去设置,默认为false,表示保持管理器设置,为true时表示横跨。
/**
* 设置是否横跨
* @param position
* @return
*/
protected boolean isFullSpanWithItemView(int position) {
return false;
}
添加菜单及菜单事件
public List<MenuItem> onCreateMultiMenuItem(int viewType) {
List<MenuItem> mm = new ArrayList<>();
mm.add(new MenuItem(R.layout.menu_item_test_delete, MenuItem.EdgeTrack.RIGHT, 01));
mm.add(new MenuItem(R.layout.menu_item_test_mark, MenuItem.EdgeTrack.RIGHT, 02));
return mm;
}
@Override
public boolean isCloseOtherItemsWhenThisWillOpen() {
return true;}adapter.setOnItemMenuClickListener(new OnItemMenuClickListener() {
@Override
public void onMenuClick(SwipeLayout swipeItemView, View itemView, View menuView, int position, int menuId) {
if (menuId == 01) {
swipeItemView.closeMenuItem();
Log.d("DEBUG", "--menu: 删除 -> position: " + position + " , menuId: " + menuId);
Toast.makeText(getContext(), "删除", Toast.LENGTH_SHORT).show();
} else if (menuId == 02) {
Log.d("DEBUG", "--menu: 关注 -> position: " + position + " , menuId: " + menuId);
Toast.makeText(getContext(), "加关注", Toast.LENGTH_SHORT).show();
}
}
});
添加粘性头部及数据绑定
注意粘性头部的Adapter
是PinnedAdapter
.
@Override
public int getPinnedItemViewLayout() {
return R.layout.item_pinned;
}
@Override
public void convertPinnedHolder(BaseViewHolder holder, int position, int type) {
holder.setText(R.id.tv_text_pinned, getItem(position).data.title);
}
概括的介绍就到这里。