RecyclerView 添加点击事件的几种方法

来源:互联网 发布:mac 穿越火线下载安装 编辑:程序博客网 时间:2024/05/17 23:35

相较于ListView,RecyclerView没有提供诸如setOnItemClickListener()方法,便捷的为每个子项添加点击事件,所以我们需要费一些功夫,手动去处理这些。

第一种方法:ViewHolder

首先是第一种方法,利用ViewHolder,直接上代码:

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {    // ...    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {        public TextView tvName;        public TextView tvHometown;        private Context context;        public ViewHolder(Context context, View itemView) {            super(itemView);            this.tvName = (TextView) itemView.findViewById(R.id.tvName);            this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);            this.context = context;            // 向每一个子项的view绑定ClickListener            itemView.setOnClickListener(this);        }        // 处理点击事件        @Override        public void onClick(View view) {            int position = getLayoutPosition(); // gets item position            User user = users.get(position);            //通过view来获取数据            Toast.makeText(context, tvName.getText(), Toast.LENGTH_SHORT).show();        }    }}

代码很直观,只需要在生成ViewHolder时,向子项的每个view绑定ClickListener,然后重写点击方法即可,同时如果我们可以在OnClick方法中去调用自定义不同接口的回调方法,来实现不同的需求。代码如下:

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {    // ...    // 定义回调的listener      private static OnItemClickListener listener;    // 定义接口    public interface OnItemClickListener {        void onItemClick(View itemView, int position);    }    // 此处用来绑定listener,根据需求的不同,传入不同的listener    public void setOnItemClickListener(OnItemClickListener listener) {        this.listener = listener;    }    public static class ViewHolder extends RecyclerView.ViewHolder {        public TextView tvName;        public TextView tvHometown;        public ViewHolder(final View itemView) {            super(itemView);            this.tvName = (TextView) itemView.findViewById(R.id.tvName);            this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);            itemView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    // Triggers click upwards to the adapter on click                    if (listener != null)                        listener.onItemClick(itemView, getLayoutPosition());                }            });        }    }}

其实和之前的代码相差不大,就是在OnClick方法中去调用了接口的方法,而这个接口方法是外部传入的,所以可以实现不同的功能,创建adapter代码如下:

ContactsAdapter adapter = ...;adapter.setOnItemClickListener(new ContactsAdapter.OnItemClickListener() {    @Override    public void onItemClick(View view, int position) {        String name = users.get(position).name;        Toast.makeText(UserListActivity.this, name + " was clicked!", Toast.LENGTH_SHORT).show();    }});

第二种方法:利用包装类

下面这种方法是来自Getting your clicks on RecyclerView,首先看使用方法:

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {    @Override    public void onItemClicked(RecyclerView recyclerView, int position, View v) {        // 此处添加点击事件    }});

接下来是包装类ItemClickSupport的实现:

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

通过源码实现可以看到这个包装类可以实现OnClick和OnLongClick两个方法,并且不需要像第一种方法一样在Adapter类中添加点击事件和传入回调接口,只需要在Activity或者Fragment中用一行简单的代码代替即可,大大增加了代码的可读性,并且使得代码更加易于维护,操作起来也更加简单。

我们跟着这个包装类的使用方法来看看原理:
首先是调用ItemClickSupport的静态方法addTo,并传入一个RecyclerView的实例,首先会判断该实例是否已经绑定了ItemClickSupport,此处我们以第一次绑定为例,此时ItemClickSupport为空,则会自动生成一个新的ItemClickSupport,调用其构造方法。

private ItemClickSupport(RecyclerView recyclerView) {   mRecyclerView = recyclerView;   mRecyclerView.setTag(R.id.item_click_support, this);   mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);}

前面两行容易理解,主要是第三行,addOnChildAttachStateChangeListener(mAttachListener),首先介绍一下OnChildAttachStateChangeListener方法:

/**     * A Listener interface that can be attached to a RecylcerView to get notified     * whenever a ViewHolder is attached to or detached from RecyclerView.     */    public interface OnChildAttachStateChangeListener {        /**         * Called when a view is attached to the RecyclerView.         *         * @param view The View which is attached to the RecyclerView         */        public void onChildViewAttachedToWindow(View view);        /**         * Called when a view is detached from RecyclerView.         *         * @param view The View which is being detached from the RecyclerView         */        public void onChildViewDetachedFromWindow(View view);    }

源码中的介绍是,当我们滑动RecyclerView时,会有新的view附着和旧的view离开,这个方法的核心就在于此,我们在onChildViewAttachedToWindow(View view)方法中,向新生成的view去绑定监听器:

public void onChildViewAttachedToWindow(View view) {   if (mOnItemClickListener != null) {       view.setOnClickListener(mOnClickListener);   }   if (mOnItemLongClickListener != null) {       view.setOnLongClickListener(mOnLongClickListener);   }}

可以看到,我们在这一步向新附着的View添加了mOnClickListener或者mOnLongClickListener,而这两个监听器是取决于我们在Activity或者Fragment传入的回调接口,回调接口可以按照项目需要进行自定义的处理。

至此,该包装类的使用方法和原理就介绍完毕。相较于第一种方法,可以发现第二种方法更加的简洁并且耦合性低,在实际项目中应该采取第二种方法较为合适。

0 0
原创粉丝点击