android技术杂荟Android知识Android开发

android中RecyclerView的Item点击、长按事件

2017-04-30  本文已影响598人  昵称真难选

原文出自王艳涛的专栏转载请注明出处!

概述

本文主要介绍android中RecyclerView的Item点击、长按事件的响应及上滑加载功能封装。之前的几篇文章从RecyclerView.Adapter的角度,先介绍了RecyclerView.Adapter的封装功能扩展,然后配合RecyclerView、SwipeRefreshLayout实现上滑加载、下拉刷新操作。从上滑加载、下拉刷新一文中,可以看到直接使用RecyclerView时有两个方面的不便:

  1. RecyclerView没有提供Item的点击、长按事件,需要自行实现。
  2. 如果软件中RecyclerView的使用比较多,需要上滑加载的场景也比较多,如果不进行封装,那么每次上滑加载时,都要写上一大段OnScrollListener重复代码,影响代码阅读。至于下拉刷新,是基于SwipeRefreshLayout完成的,不需要封装在RecyclerView中。

Item响应点击、长按事件

实现RecyclerView的Item响应点击、长按事件可以有两种思路:

  1. 从RecyclerView本身出发,借助GestureDetector类,Item的点击、长按事件,进行响应;
  2. 从上篇文章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类中,应该拥有:

  1. 包含onItemClick()方法的OnItemClickListener接口的定义;
  2. 包含onItemLongClick()方法的OnItemClickLOngListener接口的定义;
  3. OnItemClickListener接口类型的引用变量(用于接收传入的OnItemClickListener);
  4. OnItemClickLongListener接口类型的引用变量(用于接收传入的OnItemClickLongListener);
  5. 能够识别用户点击、长按并进行回调的对象,
  6. setOnItemClickListener方法
  7. 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;
      }
    }
});
上一篇下一篇

猜你喜欢

热点阅读