美文网首页android技术杂荟Android知识Android开发
android中RecyclerView的Item点击、长按事件

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

作者: 昵称真难选 | 来源:发表于2017-04-30 21:22 被阅读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;
          }
        }
    });
    

    相关文章

      网友评论

        本文标题:android中RecyclerView的Item点击、长按事件

        本文链接:https://www.haomeiwen.com/subject/pmwxtxtx.html