最完美最官方的做法给RecylerView添加点击,长按等事件

本文介绍了两种实现RecyclerView点击和长按事件的方法。一种是在Adapter中定义接口回调;另一种是通过RecyclerView.OnItemTouchListener监听,利用GestureDetector实现更高效、灵活的事件处理。

本文将介绍给RecylerView添加点击和长按事件的两种做法。


先介绍最普通的做法:

就是在adapter中写个接口,定义一个点击回调的方法,

然后在onBindViewHolder中:



class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{

//...
    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv.setText(mDatas.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    return false;
                }
            });
        }
    }
//...
}
然后在activity中:

mAdapter.setOnItemClickLitener(new OnItemClickLitener()
        {

            @Override
            public void onItemClick(View view, int position)
            {
                Toast.makeText(HomeActivity.this, position + " click",
                        Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position)
            {
                Toast.makeText(HomeActivity.this, position + " long click",
                        Toast.LENGTH_SHORT).show();
                        mAdapter.removeData(position);
            }
        });



大功告成!最普通的做法就完成了,可是这种做法非常不好,因为他会在每次复用item的时候都会给item设置一次事件监听,非常浪费。而且复用起来非常的难,你每次使用recylerview都需要这样写一次,相当麻烦,而且还不能像listview那样,直接listview.setOnItemClickListener()一下搞定。

下面介绍一种非常完美的做法,而且很官方,现在我已经完全不用上面这样笨拙的办法了,看明白下面的做法,用起来非常方便。我们需要用到 RecylerView.OnItemTouchListenenr这个类。

我们要做的就是写一个类继承RecylerView.OnItemTouchListenenr,重写其中的一些方法就可以了,这些方法是关于事件分发的,直接这样写就可以了:

  @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }


sdk 还提供了一个外部类SimpleOnGestureListener,这个类帮我们实现了手势识别的所有方法:


</pre><pre name="code" class="java">   <span style="font-size:14px;"> //用户按下屏幕就会触发
    public boolean onDown(MotionEvent e);
    //如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行
    public void onShowPress(MotionEvent e);
    //一次单独的轻击抬起操作,也就是轻击一下屏幕,就是普通点击事件
    public boolean onSingleTapUp(MotionEvent e);
    //在屏幕上拖动事件
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
    //长按触摸屏,超过一定时长,就会触发这个事件
    public void onLongPress(MotionEvent e);
    //滑屏,用户按下触摸屏、快速移动后松开
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
    //单击事件。用来判定该次点击是SingleTap而不是DoubleTap,
    //如果连续点击两次就是DoubleTap手势,如果只点击一次,
    //系统等待一段时间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,
    //然后触发SingleTapConfirmed事件
    public boolean onSingleTapConfirmed(MotionEvent e);
    //双击事件
    public boolean onDoubleTap(MotionEvent e);
    //双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作
    public boolean onDoubleTapEvent(MotionEvent e);</span>

不仅仅是点击和长按啊,非常强大。

所以我们只需要继承这个类,复写我们想要监听的操作就可以了,比如我们想要监听单击,就复写onSingleTapUp方法就可以了。

@Override
public boolean onSingleTapUp(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); //根据触摸事件的坐标值找到点击的是哪个item
     if (child!=null) {
         RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);
         onItemClick(vh);
     }
     return true;
}

这样点击事件就监听完毕,想要监听其他的,就复写其他方法。

下面给出完整的代码:

public abstract class OnRecylerViewItemClickListener implements RecyclerView.OnItemTouchListener {
    private GestureDetectorCompat mGestureDetector;
    private RecyclerView recyclerView;

    public OnRecylerViewItemClickListener(RecyclerView recyclerView){
        this.recyclerView = recyclerView;
        mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(),new ItemTouchHelperGestureListener());
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }

    private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null) {
                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);
                onItemClick(vh);
            }
            return true;
        }

        //长点击事件,本例不需要不处理
        //还可以复写其他方法,监听其他操作的回调
        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child!=null) {
                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);
                onItemLongClick(vh);
            }
        }
    }
        public abstract void onItemClick(RecyclerView.ViewHolder vh);
        public abstract void onItemLongClick(RecyclerView.ViewHolder vh);

}

如果上面的代码你没有看懂,也没关系,你只需要把下面的完整代码复制出来作为一个单独的类,在你需要设置监听的时候,在activity中调用


recyclerView.addOnItemTouchListener(new OnRecylerViewItemClickListener(recyclerView) {
            @Override
            public void onItemClick(RecyclerView.ViewHolder vh) {
                Toast.makeText(ItemTouchActivity.this,vh.getAdapterPosition()+"",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(RecyclerView.ViewHolder vh) {
                if (vh.getLayoutPosition()!=list.size()-1) {
                    helper.startDrag(vh);
                }
                Toast.makeText(ItemTouchActivity.this,vh.getAdapterPosition()+"buke",Toast.LENGTH_SHORT).show();
            }
        });




就可以了。
这样就不管有多少个recylerview都不用每次都写个接口那么麻烦,而且每次复用都设置监听对象非常浪费内存。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值