原文出自王艳涛的专栏转载请注明出处!
概述
本文主要介绍android中RecyclerView的Item点击、长按事件的响应及上滑加载功能封装。之前的几篇文章从RecyclerView.Adapter的角度,先介绍了RecyclerView.Adapter的封装和功能扩展,然后配合RecyclerView、SwipeRefreshLayout实现上滑加载、下拉刷新操作。从上滑加载、下拉刷新一文中,可以看到直接使用RecyclerView时有两个方面的不便:
- RecyclerView没有提供Item的点击、长按事件,需要自行实现。
- 如果软件中RecyclerView的使用比较多,需要上滑加载的场景也比较多,如果不进行封装,那么每次上滑加载时,都要写上一大段OnScrollListener重复代码,影响代码阅读。至于下拉刷新,是基于SwipeRefreshLayout完成的,不需要封装在RecyclerView中。
Item响应点击、长按事件
实现RecyclerView的Item响应点击、长按事件可以有两种思路:
- 从RecyclerView本身出发,借助GestureDetector类,Item的点击、长按事件,进行响应;
- 从上篇文章RecyclerView.Adapter的封装的BaseAdapter出发,借助BaseAdapter可以给Item内部控件添加事件监听的能力,向Item的根部局添加一个事件监听,从而达到使Item响应单击、长按事件;
借助GestureDetector类实现点击、长按事件监听
参考ListView的setOnClickListener()的使用方式,当想让RecyclerView的Item能够监听点击、长按事件时,需要实现一个监听接口并给RecyclerView传进去,封装后的使用方法应该如下面所示:
//单击事件
baseRecyclerView.setOnItemClickListener(new BaseRecyclerView.OnItemClickListener() {
@Override
public void onItemClick(View view, BaseHolder baseHolder, int position) {
//回调的时候能够传回点击的Item的view、holder、位置三个信息
}
});
//长按事件
recyclerView.setOnItemLongClickListener(new BaseRecyclerView.OnItemLongClickListener(){
@Override
public void onItemLongClick(View view, BaseHolder baseHolder, int position) {
//回调的时候能够传回点击的Item的view、holder、位置三个信息
}
});
所以BaseRecyclerView类中,应该拥有:
- 包含onItemClick()方法的OnItemClickListener接口的定义;
- 包含onItemLongClick()方法的OnItemClickLOngListener接口的定义;
- OnItemClickListener接口类型的引用变量(用于接收传入的OnItemClickListener);
- OnItemClickLongListener接口类型的引用变量(用于接收传入的OnItemClickLongListener);
- 能够识别用户点击、长按并进行回调的对象,
- setOnItemClickListener方法
- setOnItemLongClickListener方法。
代码如下所示。
public class BaseRecyclerView extends RecyclerView {
//OnItemClickListener接口类型的引用变量
private OnItemClickListener onItemClickListener;
//OnItemClickLongListener接口类型的引用变量
private OnItemLongClickListener onItemLongClickListener;
//能够识别用户点击、长按能够进行回调的对象
private GestureDetectorCompat gestureDetectorCompat;
//重载的构造函数
public BaseRecyclerView(Context context) {
super(context);
//获取GestureDetectorCompat实例
this.gestureDetectorCompat = getGestureDetectorCompat();
}
public BaseRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.gestureDetectorCompat = getGestureDetectorCompat();
}
public BaseRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.gestureDetectorCompat = getGestureDetectorCompat();
}
//赋值监听器
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener){
this.onItemLongClickListener = onItemLongClickListener;
}
//接口定义
public interface OnItemClickListener{
void onItemClick(View view, BaseHolder baseHolder, int position);
}
public interface OnItemLongClickListener{
void onItemLongClick(View view, BaseHolder baseHolder, int position);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
gestureDetectorCompat.onTouchEvent(e);
return false;
}
//获取GestureDetectorCompat实例
public GestureDetectorCompat getGestureDetectorCompat(){
return new GestureDetectorCompat(getContext(),
new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent e) {
//判断为单击事件
View childView = findChildViewUnder(e.getX(), e.getY());
if (childView != null &&
onItemClickListener !=null){
//回调单击事件
onItemClickListener.onItemClick(childView,
(BaseHolder)getChildViewHolder(childView),
getChildAdapterPosition(childView));
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
//判断为长按事件
View childView = findChildViewUnder(e.getX(), e.getY());
if (childView != null && onItemLongClickListener !=null){
//回调长按事件
onItemLongClickListener.onItemLongClick(childView,
(BaseHolder)getChildViewHolder(childView),
getChildAdapterPosition(childView));
}
}
});
}
}
借助BaseAdapter实现单击、长按事件监听
这种方式比较简单,在BaseAdapter中增加一个setOnClickListener()方法,让BaseAdapter持有一个View.OnClickListener的引用,然后通过BaseAdapter中onBind()方法中BaseHolder参数的setOnClickListener(int viewId, View.OnClickListener listener)方法,将监听器绑定到Item的根部局上(需要为Item的根部局赋值一个id)。
BaseAdapter改进:
//增加一个View.OnClickListener变量
View.OnClickListener onClickListener;
//增加一个setOnClickListener()
public void setOnClickListener(View.OnClickListener onClickListener){
this.onClickListener = onClickListener;
}
子类Adapter需要注意将onClickListener传给holder
@Override
public void onBind(BaseHolder holder, final Contact contact, int position) {
holder.setOnClickListener(R.id.item, onClickListener);
}
使用方法:
adapter.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//单击事件的回调
}
});
对将上滑加载事件响应进行封装
在上面BaseRecyclerView代码的基础上进行改进
//定义一个OnLoadableListener监听接口
public interface OnLoadableListener{
void load();
}
//增加一个OnLoadableListener引用变量
private OnLoadableListener onLoadableListener;
//增加一个赋值OnLoadableListener的setter方法
public void setOnLoadableListener(OnLoadableListener onLoadableListener){
this.onLoadableListener = onLoadableListener;
}
//增加一个将接收到的OnLoadableListener绑定到当前BaseRecyclerView上的函数
public void addOnLoadableListener(OnLoadableListener onLoadableListener){
addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//使用的封装的BaseAdapter适配器
if (((LinearLayoutManager)getLayoutManager()).
findLastVisibleItemPosition() == getAdapter().getItemCount()-1){
//执行加载回调操作
onLoadableListener.load();
}
}
});
}
使用方法
recyclerView.setOnLoadableListener(new BaseRecyclerView.OnLoadableListener() {
@Override
public void load() {
if (!isLoading) {
isLoading = true;
//加载操作
//……
isLoading = false;
}
}
});
网友评论