从头开始学 RecyclerView(二) 添加item点击事件
2017-04-01 13:47
465 查看
不管了,先来张图
为了节约学习时间,网上找了篇很不错的文章。这里基本就复制了。
查看RecyclerView源码可以看到,RecyclerView预留了一个Item的触摸事件方法:
通过注释我们可知,此方法是在滚动事件之前调用.需要传入一个OnItemTouchListener对象.OnItemTouchListener的代码如下:
此接口还提供了一个实现类,且官方推荐使用该实现类SimpleOnItemTouchListener,它就是一个空实现:
在触摸接口中,当触摸时会回调一个MotionEvent对象,通过使用GestureDetectorCompat来解析用户的操作.
代码实现
RecyclerItemClickListener:
RV实现:
RV实现:
这种方式,在adaper中,定义一个listener;bind-viewHolder时,对itemView添加点击监听。
在adapter的createCustomViewHolder时,传入listener
在ViewHolder中关联一个listener
相应的adaper实现:
RV实现:
这种,跟前一个,只是写法上有区别,本质一样。都是对holder.itemview添加点击监听。这里在createCustomViewHolder内,初始化了RecyclerItemClickListener.OnItemClickListener,也可以直接使用mListener,由调用adapter时传入
RV实现:
通过RecyclerView已有的方法addOnItemTouchListener()实现
对holder.ItemView添加点击监听
当ItemView attach RecyclerView时实现
从以上三种方式的实现过程可知:
三种均可实现ItemView的点击事件和长按事件的监听.
第一种方式可以很方便获取用户点击的坐标. 但不支持TV上的click事件
第二种和第三种方式可以很方便对ItemView中的子View进行监听.
第一、三种方式可以写在单独的类中,相对于第二种可使代码更独立整洁
综上所述:
如果你想监听ItemView的点击事件或长按事件,三种方式均可.
如果你只想监听ItemView中每个子View的点击事件,采用第二种或者第三种比较方便.
如果想支持TV上的click事件,只能采用第二种或第三种
http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/ 《Getting your clicks on RecyclerView》
偶吐了个槽
item点击事件必须手动添加,默认并没有一个显式的API接口可供调用。为了节约学习时间,网上找了篇很不错的文章。这里基本就复制了。
添加点击事件
RecyclerView#addOnItemTouchListener
分析查看RecyclerView源码可以看到,RecyclerView预留了一个Item的触摸事件方法:
public void addOnItemTouchListener(OnItemTouchListener listener) { mOnItemTouchListeners.add(listener); }
通过注释我们可知,此方法是在滚动事件之前调用.需要传入一个OnItemTouchListener对象.OnItemTouchListener的代码如下:
public static interface OnItemTouchListener { public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e); public void onTouchEvent(RecyclerView rv, MotionEvent e); public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept); }
此接口还提供了一个实现类,且官方推荐使用该实现类SimpleOnItemTouchListener,它就是一个空实现:
public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
在触摸接口中,当触摸时会回调一个MotionEvent对象,通过使用GestureDetectorCompat来解析用户的操作.
代码实现
RecyclerItemClickListener:
/** * from http://blog.devwiki.net/index.php/2016/07/17/Recycler-View-Adapter-ViewHolder-optimized.html * 点击事件 * Created by DevWiki on 2016/7/16. */ public class RecyclerItemClickListener extends RecyclerView.SimpleOnItemTouchListener { //public class RecyclerItemClickListener extends RecyclerView.OnItemTouchListener { private OnItemClickListener clickListener; // private GestureDetector gestureDetector; private GestureDetectorCompat gestureDetector; //v4 兼容包中 public interface OnItemClickListener { /** * 点击时回调 * * @param view 点击的View * @param position 点击的位置 */ void onItemClick(View view, int position); /** * 长点击时回调 * * @param view 点击的View * @param position 点击的位置 */ void onItemLongClick(View view, int position); } public RecyclerItemClickListener(final RecyclerView recyclerView, OnItemClickListener listener) { this.clickListener = listener; gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { 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) { View childView = rv.findChildViewUnder(e.getX(), e.getY()); if (childView != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onItemClick(childView, rv.getChildAdapterPosition(childView)); return true; } return false; } // // @Override // public void onTouchEvent(RecyclerView rv, MotionEvent e) { // // } // // @Override // public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { // // } }
RV实现:
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(mRecyclerView, new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { System.out.println("onItemClick " + adapter.getItem(position)); } @Override public void onItemLongClick(View view, int position) { System.out.println("onItemLongClick " + position); } }));
对ItemView添加点击监听
在adapter的bindCustomViewHolder()中,对holder.itemView添加监听private static class ClickAdapter extends BaseAdapter<String, SimplifyVH> { private RecyclerItemClickListener.OnItemClickListener mListener; public ClickAdapter(Context context) { super(context); } public ClickAdapter(Context context, List<String> list) { super(context, list); } public void setListener(RecyclerItemClickListener.OnItemClickListener listener) { mListener = listener; } @Override public int getCustomViewType(int position) { return 0; } @Override public SimplifyVH createCustomViewHolder(ViewGroup parent, int viewType) { return new SimplifyVH( LayoutInflater.from( parent.getContext()).inflate(R.layout.basic_simple, null, false)); } @Override public void bindCustomViewHolder(SimplifyVH holder, final int position) { holder.itemView.setFocusable(true);//加了这句,电视上就能滚动了 TextView tvTitle = (TextView) holder.itemView.findViewById(R.id.tv_title); tvTitle.setText(getItem(position)); View vImg = holder.itemView.findViewById(R.id.v_img); vImg.setBackgroundColor(getColor()); final SimplifyVH vh = (SimplifyVH) holder; vh.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onItemClick(v, position); } } }); vh.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mListener != null) { mListener.onItemLongClick(v, position); } return true; } }); } }
RV实现:
final ClickAdapter adapter = new ClickAdapter(this, mList); adapter.setListener(new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { clickAnim(view); System.out.println("onItemClick " + adapter.getItem(position)); } @Override public void onItemLongClick(View view, int position) { System.out.println("onItemLongClick " + position); } }); mRecyclerView.setAdapter(adapter);
这种方式,在adaper中,定义一个listener;bind-viewHolder时,对itemView添加点击监听。
在adapter的createCustomViewHolder时,传入listener
在ViewHolder中关联一个listener
private static class SimplifyVH extends BaseHolder { RecyclerItemClickListener.OnItemClickListener listener; public SimplifyVH(ViewGroup parent, @LayoutRes int resId) { super(parent, resId); } public SimplifyVH(View view, final RecyclerItemClickListener.OnItemClickListener listener) { super(view); this.listener = listener; view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { listener.onItemClick(v, getAdapterPosition()); } } }); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (listener != null) { listener.onItemLongClick(v, getAdapterPosition()); } return true; } }); } }
相应的adaper实现:
private static class ClickAdapter3 extends BaseAdapter<String, SimplifyVHWithListener> { private RecyclerItemClickListener.OnItemClickListener mListener; public ClickAdapter3(Context context) { super(context); } public ClickAdapter3(Context context, List<String> list) { super(context, list); } public void setListener(RecyclerItemClickListener.OnItemClickListener listener) { mListener = listener; } @Override public int getCustomViewType(int position) { return 0; } @Override public SimplifyVHWithListener createCustomViewHolder(ViewGroup parent, int viewType) { return new SimplifyVHWithListener( LayoutInflater.from( parent.getContext()).inflate(R.layout.basic_simple, null, false), new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { clickAnim(view); System.out.println("onItemClick " + getItem(position)); } @Override public void onItemLongClick(View view, int position) { System.out.println("onItemLongClick " + position + "__" + getItem(position)); } }); } @Override public void bindCustomViewHolder(SimplifyVHWithListener holder, final int position) { holder.itemView.setFocusable(true);//加了这句,电视上就能滚动了 TextView tvTitle = (TextView) holder.itemView.findViewById(R.id.tv_title); tvTitle.setText(getItem(position)); View vImg = holder.itemView.findViewById(R.id.v_img); vImg.setBackgroundColor(getColor()); } }
RV实现:
ClickAdapter3 adapter = new ClickAdapter3(this, mList); mRecyclerView.setAdapter(adapter);
这种,跟前一个,只是写法上有区别,本质一样。都是对holder.itemview添加点击监听。这里在createCustomViewHolder内,初始化了RecyclerItemClickListener.OnItemClickListener,也可以直接使用mListener,由调用adapter时传入
当ItemView attach RecyclerView时实现
主要基于RecyclerView.OnChildAttachStateChangeListener。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); } }
RV实现:
final ClickAdapter1 adapter = new ClickAdapter1(this, mList); mRecyclerView.setAdapter(adapter); ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { System.out.println("onItem " + position + " " + adapter.getItem(position)); } }).setOnItemLongClickListener(new ItemClickSupport.OnItemLongClickListener() { @Override public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) { System.out.println("onItemLongClick " + position); return true; } });
三种方式对比
以上三种方式分别是:通过RecyclerView已有的方法addOnItemTouchListener()实现
对holder.ItemView添加点击监听
当ItemView attach RecyclerView时实现
从以上三种方式的实现过程可知:
三种均可实现ItemView的点击事件和长按事件的监听.
第一种方式可以很方便获取用户点击的坐标. 但不支持TV上的click事件
第二种和第三种方式可以很方便对ItemView中的子View进行监听.
第一、三种方式可以写在单独的类中,相对于第二种可使代码更独立整洁
综上所述:
如果你想监听ItemView的点击事件或长按事件,三种方式均可.
如果你只想监听ItemView中每个子View的点击事件,采用第二种或者第三种比较方便.
如果想支持TV上的click事件,只能采用第二种或第三种
参考
http://blog.devwiki.net/index.php/2016/07/24/three-ways-click-recyclerview-item.html 《三种方式实现RecyclerView的Item点击事件》http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/ 《Getting your clicks on RecyclerView》
相关文章推荐
- RecyclerView 添加头部和尾部,并实现Item的点击事件
- Android中RecyclerView添加item的点击事件
- 关于recyclerview的横向布局的宽度以及item的点击事件的添加
- Android RecyclerView使用(二) -给Item添加点击事件
- 为RecyclerView添加item的点击事件
- 精通RecyclerView:打造ListView、GridView、瀑布流;学会添加分割线、 添加删除动画 、Item点击事件
- 给RecyclerView的Item添加点击事件
- 为RecyclerView添加item的点击事件
- RecyclerView使用(二)多种Item布局、添加点击事件
- Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件
- RecyclerView 给Item添加点击事件
- RecyclerView加载不同item并实现其item点击事件,实现添加常用应用的功能
- 为RecyclerView添加item的点击事件
- Android中RecyclerView的item中控件的点击事件添加删除一行、上移下移一行的代码实现
- [Android | Material Design] RecyclerView Item点击事件 添加水波纹效果 两种办法
- 初识RecyclerView(二)——添加item的点击事件
- 为RecyclerView添加item的点击事件
- 给RecyclerView的item添加点击监听事件
- 为RecyclerView添加item的点击事件(转载)
- 为RecyclerView添加item的点击事件