从头开始学 RecyclerView(二) 添加item点击事件

不管了,先来张图

偶吐了个槽



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添加点击监听。

当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;
    }
});

三种方式对比

以上三种方式分别是:

  1. 通过RecyclerView已有的方法addOnItemTouchListener()实现
  2. 对holder.ItemView添加点击监听
  3. 当ItemView attach RecyclerView时实现

从以上三种方式的实现过程可知:

  1. 三种均可实现ItemView的点击事件和长按事件的监听.
  2. 第一种方式可以很方便获取用户点击的坐标. 但不支持TV上的click事件
  3. 第二种和第三种方式可以很方便对ItemView中的子View进行监听.
  4. 第一、三种方式可以写在单独的类中,相对于第二种可使代码更独立整洁

综上所述:

如果你想监听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》

时间: 2024-12-24 20:02:10

从头开始学 RecyclerView(二) 添加item点击事件的相关文章

Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

1. 引言: RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一下观察者模式. 2. 最终目的 模拟ListView的setOnItemClickListener()方法,调用者只须调用类似于setOnItemClickListener的东西就能获得被点击item的相关数据.   3. 原理 为RecyclerView的每个子item设置setOnClickLi

在ViewHolder中添加item点击事件接口(自定义

在Adapter中定义接口并提供回调static class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { private List<String> mList; private Context mContext; private OnItemClickListener mOnItemClickListener; public HomeAdapter(List<String> l

精通RecyclerView:打造ListView、GridView、瀑布流;学会添加分割线、 添加删除动画 、Item点击事件

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53126706 本文出自[DylanAndroid的博客] 精通RecyclerView:打造ListView.GridView.瀑布流:学会添加分割线. 添加删除动画 .Item点击事件 在上一篇Android用RecyclerView练手仿美团分类界面写了RecyclerView的基本用法, 今天想想,在这里重新学习一下RecyclerView的完整用法.包括如何打造一个普

从头开始学JavaScript (二)——变量及其作用域

原文:从头开始学JavaScript (二)--变量及其作用域 一.变量 ECMAscript变量是松散型变量,所谓松散型变量,就是变量名称可以保存任何类型的数据,每个变量仅仅是一个用于保存值的占位符. 定义:var firstDemo; 二.变量的作用域 2.1基本概念 使用var 定义变量:定义该变量的作用域的局部变量,这种定义变量的方法也被成为显式声明. 这么说不理解的话可以看看下面这个简单粗暴的例子: test();function test(){var firstDemo="hello

从源码角度入手实现RecyclerView的Item点击事件

转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6758373.html RecyclerView 作为 ListView 和 GridView 的替代产物,相信在Android界已广为流传. RecyclerView 本是不会有类似 ListView 的那种点击事件,但是知道和会用又是两种情况,跟随我一起从源码角度分析,RecyclerView 点击事件. 首先看一下 Google 对 ListView 家族谱的介绍: 可以看出 ListView 归根

后台找到repeater里面的div并添加客户端点击事件

public partial class Inv_SelectWorkservice : System.Web.UI.Page,IPostBackEventHandler{ } 通过OnItemCreated 找到repeater里面的div并添加客户端点击事件div要加上runat="server" id="itemTy" onclick="test" 后台: protected void Repeater2_ItemCreated(objec

iOS 为自定义tableView添加button点击事件后获取其序号

在自定义tableView中,为cell添加button点击事件后,如何获取其对应的序号? 1.创建tableView: 先创建一个成员变量: @interface MyCameraViewController ()<UITableViewDelegate,UITableViewDataSource> { UITableView *_tableView; }@end 在viewDidLoad中初始化 _tableView = [[UITableView alloc] initWithFrame

Android实现RecyclerView自定义列表、点击事件以及下拉刷新

Android使用RecyclerView 1. 什么是RecyclerView RecyclerView 是 Android-support-v7-21 版本中新增的一个 Widgets,官方对于它的介绍则是:RecyclerView 是 ListView 的升级版本,更加先进和灵活. 简单来说就是:RecyclerView是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式.它被作为ListView和GridView控件的继承者,在最新的support-V7版本中提供支持. 2.

ListView的Item点击事件(消息传递)

转载请保留原文出处“http://my.oschina.net/gluoyer/blog”,谢谢! 您可以到博客的“友情链接”中,“程序猿媛(最新下载)*.*”下载最新版本,持续更新!当前版本,也可直接点击“当前1.5版本”下载.     引子:自定义ListView的Adapter,给Item中的子控件(按钮.图标.文字等)添加点击事件,来进行点击后的不同处理,是经常要做的事情.但有些需要在处理事件中,对Activity中其他控件进行更新的话,通常把Adapter在Activity中实现,处理