今天来学习一下如何实现RecyclerView的Item的点击事件.实现Item的点击事件有三种方式:
1. 通过RecyclerView已有的方法addOnItemTouchListener()实现
2. 在创建ItemView时添加点击监听
3. 当ItemView attach RecyclerView时实现
1. 通过RecyclerView的addOnItemTouchListener()实现
1.1 查看源码
查看RecyclerView源码可以看到,RecyclerView预留了一个Item的触摸事件方法:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | /** * 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(OnItemTouchListener listener) { mOnItemTouchListeners.add(listener); } |
通过注释我们可知,此方法是在滚动事件之前调用.需要传入一个OnItemTouchListener对象.OnItemTouchListener的代码如下:
[代码]java代码:
1 2 3 4 5 6 7 8 | public static interface OnItemTouchListener {
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);
public void onTouchEvent(RecyclerView rv, MotionEvent e);
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept); } |
此接口还提供了一个实现类,且官方推荐使用该实现类SimpleOnItemTouchListener
在触摸接口中,当触摸时会回调一个MotionEvent对象,通过使用GestureDetectorCompat来解析用户的操作.
1.2 实现点击事件监听
写一个ItemClickListener类继承SimpleOnItemTouchListener,构造时传入RecyclerView对象和Item点击回调,并覆写父类的boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)方法,具体代码如下:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /** * 点击事件 * Created by DevWiki on 2016/7/16. */
public class ItemClickListener extends RecyclerView.SimpleOnItemTouchListener {
private OnItemClickListener clickListener; private GestureDetectorCompat gestureDetector;
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position); }
public ItemClickListener(final RecyclerView recyclerView, OnItemClickListener listener) { this.clickListener = listener; gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { View childView = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (childView != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onItemClick(childView, recyclerView.getChildAdapterPosition(childView)); } return true; }
@Override public void onLongPress(MotionEvent e) { View childView = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (childView != null && clickListener != null) { clickListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView)); } } }); }
@Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { gestureDetector.onTouchEvent(e); return false; } } |
在GestureDetectorCompat的手势回调中我们覆写:
1. boolean onSingleTapUp(MotionEvent e)单击抬起回调
2. void onLongPress(MotionEvent e)长按回调
1.3 使用事件监听
在RecyclerView的对象中添加addOnItemTouchListener()方法,然后在回调中处理你需要的事件:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | recyclerView.addOnItemTouchListener(new SingleItemClickListener(recyclerView, new SingleItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) { DevLog.i("touch click name:" + position); Toast.makeText(SingleActivity.this, "touch click:" + position, Toast.LENGTH_SHORT).show(); }
@Override public void onItemLongClick(View view, int position) { DevLog.i("touch long click:" + position); Toast.makeText(SingleActivity.this, "touch long click:" + position, Toast.LENGTH_SHORT).show(); } })); |
2. 在创建ItemView时添加点击监听
这种方法和ListView一样,在Adapter里面创建View时添加点击事件.比如:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | @Override public void bindCustomViewHolder(SingleHolder holder, final int position) { Person person = getItem(position); holder.nameView.setText(person.getName()); holder.ageView.setText(String.valueOf(person.getAge()));
if (clickListener != null) { holder.nameView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clickListener.onNameClick(position); } }); holder.ageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clickListener.onAgeClick(position); } }); } } |
然后在Adapter对象上添加监听回调:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 | singleAdapter.setClickListener(new SingleAdapter.OnSingleItemClickListener() { @Override public void onNameClick(int position) { DevLog.i("adapter click name:" + position); Toast.makeText(SingleActivity.this, "adapter click name:" + position, Toast.LENGTH_SHORT).show(); }
@Override public void onAgeClick(int position) { DevLog.i("adapter click age:" + position); Toast.makeText(SingleActivity.this, "adapter click name:" + position, Toast.LENGTH_SHORT).show(); } }); |
3. 当ItemView attach RecyclerView时实现
该实现方法是在阅读国外的一篇博客时发现的,原文链接如下:Getting your clicks on RecyclerView
实现的代码如下:
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | public class ItemClickSupport { private final RecyclerView mRecyclerView; private OnItemClickListener mOnItemClickListener; private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (mOnItemClickListener != null) { RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v); mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v); } } };
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mOnItemLongClickListener != null) { RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v); return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v); } return false; } };
private RecyclerView.OnChildAttachStateChangeListener mAttachListener = new RecyclerView.OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(View view) { if (mOnItemClickListener != null) { view.setOnClickListener(mOnClickListener); } if (mOnItemLongClickListener != null) { view.setOnLongClickListener(mOnLongClickListener); } }
@Override public void onChildViewDetachedFromWindow(View view) {} };
private ItemClickSupport(RecyclerView recyclerView) { mRecyclerView = recyclerView; mRecyclerView.setTag(R.id.item_click_support, this); mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener); }
public static ItemClickSupport addTo(RecyclerView view) { ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); if (support == null) { support = new ItemClickSupport(view); } return support; }
public static ItemClickSupport removeFrom(RecyclerView view) { ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); if (support != null) { support.detach(view); } return support; }
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; return this; }
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) { mOnItemLongClickListener = listener; return this; }
private void detach(RecyclerView view) { view.removeOnChildAttachStateChangeListener(mAttachListener); view.setTag(R.id.item_click_support, null); }
public interface OnItemClickListener { void onItemClicked(RecyclerView recyclerView, int position, View v); }
public interface OnItemLongClickListener { boolean onItemLongClicked(RecyclerView recyclerView, int position, View v); } } |
上面的代码中给RecyclerView设置了OnChildAttachStateChangeListener事件监听,当子View attach RecyclerView时设置事件监听.
[代码]java代码:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | private RecyclerView.OnChildAttachStateChangeListener mAttachListener = new RecyclerView.OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(View view) { if (mOnItemClickListener != null) { view.setOnClickListener(mOnClickListener); } if (mOnItemLongClickListener != null) { view.setOnLongClickListener(mOnLongClickListener); } }
@Override public void onChildViewDetachedFromWindow(View view) {} }; |
4. 三种方式对比
以上三种方式分别是:
1. 通过RecyclerView已有的方法addOnItemTouchListener()实现
2. 在创建ItemView时添加点击监听
3. 当ItemView attach RecyclerView时实现
从以上三种方式的实现过程可知:
1. 三种均可实现ItemView的点击事件和长按事件的监听.
2. 第一种方式可以很方便获取用户点击的坐标.
3. 第二种和第三种方式可以很方便对ItemView中的子View进行监听.
4. 第一种方式和第三种方式可以写在单独的类中,相对于第二种写在Adapter的方式可使代码更独立整洁
综上所述:
如果你只想监听ItemView的点击事件或长按事件,三种方式均可.
如果你想监听ItemView中每个子View的点击事件,采用第二种或者第三种比较方面.