美文网首页android UI系列专题
Android小记:RecyclerView添加Item点击事件

Android小记:RecyclerView添加Item点击事件

作者: 喝牛奶的小饼干 | 来源:发表于2020-04-09 17:38 被阅读0次

    自从Android5.0,Google发布RecyclerView以来,逐渐代替了传统的ListView,因为RecyclerView更加强大,更加灵活,但是,由于官方未实现RecyclerView的Item点击事件,所以需要自行实现。下面就是我在使用RecyclerView的过程中,总结的添加点击事件的几种方法。

    方式一:通过RecyclerView的addOnItemTouchListener()方法

    使用RecyclerView提供的addOnItemTouchListener()方法,为Item添加触摸回调,在触摸事件处理中,实现Item点击;
    通过源码得知,RecyclerView有一个添加Item触摸事件的方法:

    /**
     * Add an {@link OnItemTouchListener} to intercept touch events before they are dispatched
     * to child views or this view's standard scrolling behavior.
     *
     * <p>Client code may use listeners to implement item manipulation behavior. Once a listener
     * returns true from
     * {@link OnItemTouchListener#onInterceptTouchEvent(RecyclerView, MotionEvent)} its
     * {@link OnItemTouchListener#onTouchEvent(RecyclerView, MotionEvent)} method will be called
     * for each incoming MotionEvent until the end of the gesture.</p>
     *
     * @param listener Listener to add
     * @see SimpleOnItemTouchListener
     */
    public void addOnItemTouchListener(@NonNull OnItemTouchListener listener) {
        mOnItemTouchListeners.add(listener);
    }
    

    此方法需要传入一个OnItemTouchListener,OnItemTouchListener代码如下:

    public interface OnItemTouchListener {
        boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
        void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
        void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
    }
    

    同时,RecyclerView还提供了一个子类SimpleOnItemTouchListener

    /**
     * An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method 
     * bodies and default return values.
     * <p>
     * You may prefer to extend this class if you don't need to override all methods. Another
     * benefit of using this class is future compatibility. As the interface may change, we'll
     * always provide a default implementation on this class so that your code won't break when
     * you update to a new version of the support library.
     */
    public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener {
        @Override
        public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
            return false;
        }
        @Override
        public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
        }
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        }
    }
    

    我们可以通过此类实现Item点击功能;
    写一个类ItemTouchHelper类继承自SimpleOnItemTouchListener,重写onInterceptTouchEvent方法,在onInterceptTouchEvent中进行事件处理;

    @Override
    public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
                                         @NonNull MotionEvent motionEvent) {
        return mGestureDetectorCompat.onTouchEvent(motionEvent);
    }
    

    这里的mGestureDetectorCompat,是一个GestureDetectorCompat辅助工具,继续观察源码,GestureDetectorCompat构造器中需要我们传入ContextOnGestureListener,下面是OnGestureListener源码:

    public interface OnGestureListener {
        // 用户按下屏幕就会触发
        boolean onDown(MotionEvent e);
        // 如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行
        void onShowPress(MotionEvent e);
        // 一次单独的轻击抬起操作,也就是轻击一下屏幕,就是普通点击事件
        boolean onSingleTapUp(MotionEvent e);
        // 在屏幕上拖动事件
        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
        // 长按触摸屏,超过一定时长,就会触发这个事件
        void onLongPress(MotionEvent e);
        // 滑屏,用户按下触摸屏、快速移动后松开
        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
    }
    

    通过源码发现,onSingleTapUp方法会在触摸抬起时触发;同样,官方也为我们提供了一个OnGestureListener的简单实现类SimpleOnGestureListener,这个类实现了所有方法,但都是空实现,我们只需要重写onSingleTapUp方法,并处理事件即可:

    GestureDetector.OnGestureListener gl = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onItemClick(recyclerView.getChildViewHolder(child));
                return true;
            }
            return false;
        }
    }
    
    mGestureDetectorCompat = new GestureDetectorCompat(recyclerView.getContext(), gl);
    

    RecyclerView提供了findChildViewUnder方法,我们可以通过事件点击的坐标获取点击的Item,再通过RecyclerView的getChildViewHolder方法获取Item的ViewHolder,进而执行我们想要的操作,至此,我们可以将点击事件回调出去。方法一:通过View.setOnClickListener()方法

    方式二:将点击事件添加到Item的根布局上,通过Adapter回调的方式添加事件监听:
    public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
        
        ...
      
        @Override
        public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int position) {
            viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (listener != null) {
                        listener.onItemClick(viewHolder.itemView, viewHolder.getAdapterPosition());
                    }
                }
            });
        }
    
        private OnItemClickListener listener;
    
        public void setOnItemClickListener(OnItemClickListener listener) {
            this.listener = listener;
        }
    
        public interface OnItemClickListener {
            void onItemClick(View itemView, int position);
        }
    }
    
    方式三:在Item添加到RecyclerView时添加点击事件

    RecyclerView还提供了一个addOnChildAttachStateChangeListener方法,可以为RecyclerView提供一个OnChildAttachStateChangeListener,监听一个View添加到RecyclerView和离开RecyclerView,我们可以在这个时候执行一些操作来实现Item点击:

    OnChildAttachStateChangeListener listener = new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(@NonNull View view) {
            final RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(view);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mListener != null){
                        mListener.onItemClick(viewHolder);
                    }
                }
            });
        }
    
        @Override
        public void onChildViewDetachedFromWindow(@NonNull View view) {}
    }
    mRecyclerView.addOnChildAttachStateChangeListener(listener);
    

    小结

    以上三种实现方式是在开发中遇到,并在网上获取的实现方法,三种方式各有优劣,在实际开发中,可以灵活选择。

    第一种直接从触摸事件入手,可举一反三,通过不同的逻辑进行其他手势的监听和处理;第二种和第三种大同小异,均是通过View类的setOnClickListener方法入手实现,同样的也可以通过其他方式实现不同效果。


    本文仅代表个人看法,如果有误欢迎指正,如果您有更好的实现,欢迎指教,谢谢!

    相关文章

      网友评论

        本文标题:Android小记:RecyclerView添加Item点击事件

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