RecyclerView onClick
有没有人使用RecyclerView
find一种方法来设置一个onClickListener
项目在RecyclerView
? 我想为每个项目的每个布局设置一个监听器,但这看起来有点太麻烦了,我确信RecyclerView
有一个方法来监听onClick
事件,但是我无法弄清楚。
由于API已经发生了根本性的变化,如果您要为每个项目创build一个OnClickListener
,则不会感到意外。 这不是一个麻烦虽然。 在你的RecyclerView.Adapter<MyViewHolder>
实现中,你应该有:
private final OnClickListener mOnClickListener = new MyOnClickListener(); @Override public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false); view.setOnClickListener(mOnClickListener); return new MyViewHolder(view); }
onClick
方法:
@Override public void onClick(final View view) { int itemPosition = mRecyclerView.getChildLayoutPosition(view); String item = mList.get(itemPosition); Toast.makeText(mContext, item, Toast.LENGTH_LONG).show(); }
这是一个更好,不太紧密的方式来实现RecyclerView
的OnClickListener
。
使用片段:
RecyclerView recyclerView = findViewById(R.id.recycler); recyclerView.addOnItemTouchListener( new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { // do whatever } @Override public void onLongItemClick(View view, int position) { // do whatever } }) );
RecyclerItemClickListener
实现:
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { public void onItemClick(View view, int position); public void onLongItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null && mListener != null) { mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); return true; } return false; } @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } @Override public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){} }
基于Jacob Tabak的回答(他为+1),我能够添加onLongClick监听器:
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { public interface OnItemClickListener { void onItemClick(View view, int position); void onItemLongClick(View view, int position); } private OnItemClickListener mListener; private GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, 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 && mListener != null) { mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); } return false; } @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }
那么你可以像这样使用它:
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { // ... } @Override public void onItemLongClick(View view, int position) { // ... } }));
查看类似的问题 @ CommonsWare的评论链接,它实现了OnClickListener
中的viewHolder
接口。
以下是一个ViewHolder
的简单例子:
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView mTextView; private ViewHolder(View itemView, TextView textView) { super(itemView); itemView.setOnClickListener(this); mTextView = textView; } @Override public void onClick(View view) { Toast.makeText(view.getContext(), "position = " + getPosition(), Toast.LENGTH_SHORT).show(); } }
Adapter
然后看起来像这样:
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false); TextView textView = (TextView) view.findViewById(android.R.id.text1); return new ViewHolder(view, textView); }
我这样做,没有不适当的类,探测器等简单的代码在我们的适配器。 特别是比以前更好的LongClick解决scheme。
public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> { private static ClickListener clickListener; public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { TextView name; public ViewHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); itemView.setOnLongClickListener(this); name = (TextView) itemView.findViewById(R.id.card_name); } @Override public void onClick(View v) { clickListener.onItemClick(getAdapterPosition(), v); } @Override public boolean onLongClick(View v) { clickListener.onItemLongClick(getAdapterPosition(), v); return false; } } public void setOnItemClickListener(ClickListener clickListener) { PasswordAdapter.clickListener = clickListener; } public interface ClickListener { void onItemClick(int position, View v); void onItemLongClick(int position, View v); } }
然后在片段或活动中,只需点击:
PasswordAdapter mAdapter = ...; mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() { @Override public void onItemClick(int position, View v) { Log.d(TAG, "onItemClick position: " + position); } @Override public void onItemLongClick(int position, View v) { Log.d(TAG, "onItemLongClick pos = " + } });
这是为我工作。 将OnClickListener
附加到onBindView
。 我真的不知道这是否会影响性能,但似乎很less用代码工作。
public void onBindViewHolder(ViewHolder holder, final int position) { holder.view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show(); } }); }
这对我来说是非常困难的,在活动中的项目点击监听器,也有点击监听器的单一视图的项目不会触发项目点击监听器。 在雅各布·塔巴克的回答中玩了一遍之后,如果没有其他的项目内的触摸动作被提出,我尊重他对于项目点击的回答。
我有一个自定义的OnClickListener
接口,它具有项目单击事件,该事件包含从适配器中单击的项目视图和项目位置。 我在构造函数中展示它的一个实例(或者可以使用setter),并将其附加到视图持有者容器单击侦听器。
我也有适配器中的其他点击侦听器(可以在视图持有人),将处理当前查看点击从容器。
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> { private ArrayList<String> mData; private OnItemClickListener mOnItemClickListener; public interface OnItemClickListener { public void onItemClick(View view, int position); } public MyRecyclerAdapter(ArrayList<String> itemsData, OnItemClickListener onItemClickListener) { mOnItemClickListener = onItemClickListener; this.mData = itemsData; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View layoutView = LayoutInflater.from(mContext).inflate( R.layout.list_item, parent, false); MyViewHolder viewHolder = new MyViewHolder(layoutView); return viewHolder; } @Override public void onBindViewHolder(MyViewHolder viewHolder, final int position) { viewHolder.container.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mOnItemClickListener.onItemClick(v, position); } }); viewHilder.button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //do button click work here } }); } @Override public int getItemCount() { return mData.size(); }}
在活动中,您需要通过传递OnItemClickListener
实例来初始化适配器
public class FeedActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); ..... MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() { @Override public void onItemClick(View view, int position) { ///list item was clicked } }); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(mFeedsAdapter); }
和我的ViewHolder
public class MyViewHolder extends RecyclerView.ViewHolder { public Button button; public View container; public MyViewHolder(View itemLayoutView) { super(itemLayoutView); container = itemLayoutView; button = (Button) itemLayoutView.findViewById(R.id.button); }}
对于RecyclerView
的onItemClickListener
项目和子项目,我有很好的解决scheme
第1步 –创build一个界面
public interface OnRecyclerViewItemClickListener { /** * Called when any item with in recyclerview or any item with in item * clicked * * @param position * The position of the item * @param id * The id of the view which is clicked with in the item or * -1 if the item itself clicked */ public void onRecyclerViewItemClicked(int position, int id); }
第2步然后按照以下方式在适配器的onBindViewHolder
方法中使用它
/** * Custom created method for Setting the item click listener for the items and items with in items * @param listener OnRecyclerViewItemClickListener */ public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) { this.listener = listener; } @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { // viewHolder.albumBg.setBackgroundResource(_itemData[position] // .getImageUrl()); viewHolder.albumName.setText(arrayList.get(position).getName()); viewHolder.artistName.setText(arrayList.get(position).getArtistName()); String imgUrl = arrayList.get(position).getThumbImageUrl(); makeImageRequest(imgUrl, viewHolder); viewHolder.parentView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.onRecyclerViewItemClicked(position, -1); } }); viewHolder.settingButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.onRecyclerViewItemClicked(position, v.getId()); } }); } // class to hold a reference to each item of RecyclerView public static class ViewHolder extends RecyclerView.ViewHolder { public TextView albumName, artistName; public ImageView albumIcon, settingButton; public LinearLayout parentView; public ViewHolder(View itemLayoutView) { super(itemLayoutView); // albumBg = (LinearLayout) itemLayoutView // .findViewById(R.id.albumDlbg); albumName = (TextView) itemLayoutView.findViewById(R.id.albumName); artistName = (TextView) itemLayoutView .findViewById(R.id.artistName); albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon); parentView = (LinearLayout) itemLayoutView .findViewById(R.id.albumDlbg); settingButton = (ImageView) itemLayoutView .findViewById(R.id.settingBtn); } }
第3步 –find并设置回收站视图在您使用此的活动或片段
recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs); lm = new LinearLayoutManager(mActivity); lm.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(lm); recyclerView.addItemDecoration( new HorizontalDividerItemDecoration.Builder(getActivity()) .paint(Utils.getPaint()).build()); PopularSongsadapter mAdapter = new PopularSongsadapter(gallery, mActivity, true); // set adapter recyclerView.setAdapter(mAdapter); mAdapter.setOnItemClickListener(this); // set item animator to DefaultAnimator recyclerView.setItemAnimator(new DefaultItemAnimator());
第4步最后在您使用recyclerview的活动或片段中实现接口
@Override public void onRecyclerViewItemClicked(int position, int id) { if(id==-1){ Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show(); } }
这是我最终需要的,以防有人发现它有用:
public static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View item) { super(item); item.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.d("RecyclerView", "onClick:" + getPosition()); } }); } }
资料来源: http : //blog.csdn.net/jwzhangjie/article/details/36868515
这是我做的。 此解决scheme同时支持RecyclerView项目和视图内部的onClick和onLongClick内部RecyclerView项目(内部视图)。
我在我select的视图上标记viewHolder:
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null); ViewHolder viewHolder = new ViewHolder(itemView); itemView.setOnClickListener( this); itemView.setOnLongClickListener(this); viewHolder.imageIV.setOnClickListener(this); viewHolder.imageIV.setOnLongClickListener(this); viewHolder.imageIV.setTag(viewHolder); itemView.setTag(viewHolder); return viewHolder; }
我使用holder.getPosition()来检索onClick()方法中的位置(onLongClick类似):
public void onClick(View view) { ViewHolder holder = (ViewHolder) view.getTag(); int position = holder.getPosition(); if (view.getId() == holder.imageIV.getId()){ Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show(); } }
getChildPosition的变体也可以。 请注意,对于内部视图,在onClick()中使用:
int position = recyclerView.getChildPosition((View)view.getParent());
在我看来,这个解决scheme的优点是,当点击图像时,只有onclick()图像监听器被调用,而当我将Jacob的解决scheme组合为RecyclerView Item视图和我的内部视图解决scheme时,RecyclerView Item视图onclick )也被称为(当点击图片时)。
要做到这一点要简单得多。 只onBindViewHolder
在根视图上点击onBindViewHolder
。
考虑这是你对适配器的看法,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/linearlayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:textSize="15sp" /> </LinearLayout>
然后在你的适配器中执行
//get the layout and make view holder @Override public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null); ViewHolder1 viewHolder = new ViewHolder1(view); return viewHolder; } @Override public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) { //apply on click on your root view holder.linearlayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Do on click stuff } }); } //make references to views in layout including root view public class ViewHolder1 extends RecyclerView.ViewHolder { protected LinearLayout linearlayout = null protected TextView textview = null; public CareerLinksViewHolder(View itemView) { super(itemView); this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout); this.tvCompName = (TextView) itemView.findViewById(R.id.textview); } }
方法太简单有效。
而不是在视图持有人内部实现接口View.OnClickListener
或者在你的活动中创build和实现接口并实现接口 – 我在OnClickListener
实现上使用了这个代码。
public static class SimpleStringRecyclerViewAdapter extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> { // Your initializations goes here... private List<String> mValues; public static class ViewHolder extends RecyclerView.ViewHolder { //create a variable mView public final View mView; /*All your row widgets goes here public final ImageView mImageView; public final TextView mTextView;*/ public ViewHolder(View view) { super(view); //Initialize it here mView = view; /* your row widgets initializations goes here mImageView = (ImageView) view.findViewById(R.id.avatar); mTextView = (TextView) view.findViewById(android.R.id.text1);*/ } } public String getValueAt(int position) { return mValues.get(position); } public SimpleStringRecyclerViewAdapter(Context context, List<String> items) { mBackground = mTypedValue.resourceId; mValues = items; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item, parent, false); view.setBackgroundResource(mBackground); return new ViewHolder(view); } @Override public void onBindViewHolder(final ViewHolder holder, int position) { holder.mBoundString = mValues.get(position); holder.mTextView.setText(mValues.get(position)); //Here it is simply write onItemClick listener here holder.mView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Context context = v.getContext(); Intent intent = new Intent(context, ExampleActivity.class); context.startActivity(intent); } }); } @Override public int getItemCount() { return mValues.size(); } }
到目前为止发布的所有答案都是很好的解决scheme,但是如果您不想处理太多的实现细节,并且希望它与ListView的工作方式类似,那么我将推荐使用TwoWay-View,如下所示:
https://github.com/lucasr/twoway-view
请注意,此实现还支持长按项目,以及支持按下状态(这是重要的,这个问题的其他解决scheme是缺乏的)。
如果您不想使用整个库,请查看ClickItemTouchListener类,如果需要,可以将其用作独立程序。 我现在发现的唯一问题是长按+滚动,似乎有不正确的行为。
你可以实现OnClickListener到你的ViewHolder类
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public Item item @InjectView(R.id.tv_title) public TextView tvTitle; @InjectView(R.id.rl_row) public RelativeLayout rlRow; public ViewHolder(View v) { super(v); ButterKnife.inject(this, v); v.setOnClickListener(this); } @Override public void onClick(View view) { Log.e("item title",item.getTitle()); } }
并onBindViewHolder设置您的查看持有人的项目
public void onBindViewHolder(ViewHolder holder, int position) { holder.tvTitle.setText(objects.get(position).getTitle()); holder.item = objects.get(position); }
如果你想捕捉点击事件单个项目,然后只是在ViewHolder
类中实现OnClickListener
,然后设置单个视图或整个ViewHolder
点击侦听器。
以下示例显示相同
public class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener { TextView txt_title,txt_name,txt_email; public ContactViewHolder(View itemView) { super(itemView); txt_title = (TextView)itemView.findViewById(R.id.txt_title); txt_name = (TextView)itemView.findViewById(R.id.txt_name); txt_email = (TextView)itemView.findViewById(R.id.txt_email); txt_name.setOnClickListener(this); txt_email.setOnClickListener(this); itemView.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub if(v == itemView) { Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show(); } if(v == txt_name) { Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show(); } if(v == txt_email) { Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show(); } } } }
RecyclerView
没有OnClickListener
,必须自己实现。
我喜欢在Adapter
添加一个OnItemClickListener
接口,并在点击ViewHolder
的项目视图时调用onClick
方法。 因此pipe理项目点击的责任在ViewHolder
和Adapter
。 将活动或片段,将决定如何做
将接口添加到侦听器和侦听器对象。
public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> { ... private static OnItemClickListener onItemClickListener; ... public static interface OnItemClickListener { public void onItemClick(View view, int position); } ... }
我们捕获该项目的根视图的点击,并在适配器上触发onClick
监听器调用时触发callback。
public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> { ... private static OnItemClickListener onItemClickListener; ... public static interface OnItemClickListener { public void onItemClick(View view, int position); } ... public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public ViewHolder(View itemRootView) { super(itemRootView); imageView = (ImageView) itemRootView.findViewById(R.id.itemImage); itemRootView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = ViewHolder.super.getAdapterPosition(); onItemClickListener.onItemClick(view,position); } }); } } }
由于活动或片段,在我们的案例中,我们分配一个监听器到适配器和onClickcallback,我们将按位置获取选定的项目,并打开项目的详细活动。
public class ItemsFragment extends Fragment { ... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ... ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { //Do something when an item has been clicked } }); ... } ... }
您可以将一个clickListener
给Adapter
。
在您的Activity
:
private View.OnClickListener mItemClick = new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = null; int position = list.getChildPosition(v); switch (position) { case 0: intent = new Intent(MainActivity.this, LeakCanaryActivity.class); break; case 1: intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class); break; } if (intent != null) { MainActivity.this.startActivity(intent); } } };
然后传递给Adapter
:
MainAdapter mainAdapter = new MainAdapter(this, mItemClick);
在Adapter
的onCreateViewHolder
:
@Override public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) { View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false); ViewHolder holder = new ViewHolder(itemView); itemView.setOnClickListener(mItemClick); return holder; }
Unfortunately RecyclerView
is missing a couple of features that ListView
had built-in. For example the ability to add an OnItemClickListener
that triggers when an item is clicked. RecyclerView
allows you to set an OnClickListener
in your adapter, but passing on that click listener from your calling code, to the adapter and to the ViewHolder
, is complicated for catching a simple item click.
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); } }
You also need to define R.id.item_click_support
using ids.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="item_click_support" type="id" /> </resources>
The resulting code click listener now looks like this:
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { // do it } });
For Brief Explanation about recyclerview clicks please have a look at this littlerobots_blog
For me, this is the best way:
class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener { ... @Override public void onClick(View view) { int itemPosition = vRecycle.getChildPosition(view); //And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback } ... }
Here is what I did Read more & download the gist here
Adding the same here
CustomItemClickListener.java
public interface CustomItemClickListener { public void onItemClick(View v, int position); }
ItemsListAdapter.java
public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> { ArrayList<ItemListSingleItem> data; Context mContext; CustomItemClickListener listener; @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false); final ViewHolder mViewHolder = new ViewHolder(mView); mView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.onItemClick(v, mViewHolder.getPosition()); } }); return mViewHolder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle())); if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) { // I Love picasso library :) http://square.github.io/picasso/ Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image). placeholder(R.drawable.ic_no_image). transform(new RoundedCornersTransformation(5, 0)). into(holder.thumbnailImage); } else { holder.thumbnailImage.setImageResource(R.drawable.ic_no_image); } } @Override public int getItemCount() { return data.size(); } public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) { this.data = data; this.mContext = mContext; this.listener = listener; } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView itemTitle; public ImageView thumbnailImage; ViewHolder(View v) { super(v); itemTitle = (TextView) v .findViewById(R.id.post_title); thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image); } } }
From most of the answers above, they seem to be setting their onclicklisteners to individual items. However, the solution am about to offer is very simple but yet not intuitive to many. Many are forgetting that the other components are always in a parent component which is used to display items in the List or Recycler views. This solution is just about setting a single onclick listener to this parent view and the turn is played. The solution also includes a way to pass the position of the item being clicked on from the list or recycler view. Here, our main rootview is a CardView from the android support library. Here is sample code
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> { public static final String LOG_TAG = ListAdapter.class.getSimpleName(); private Cursor mDataset; private Context mContext; private ViewHolder mViewHolder; // Provide a suitable constructor (depends on the kind of dataset) public ListAdapter(Context context, Cursor Dataset) { mDataset = Dataset; mContext = context; } // Create new views (invoked by the layout manager) @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_business_view, parent, false); mViewHolder = new ViewHolder(v); return mViewHolder; } public void setData(Cursor newdata) { this.mDataset = newdata; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder holder, int position) { //Bind data to other items here. To save time, i have ommited that. //here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item. holder.card.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show(); } }); } } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { if (null != mDataset) { return mDataset.getCount(); } return 0; } // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class ViewHolder extends RecyclerView.ViewHolder{ // each data item is just a string in this case public final TextView mBusinesssName; // View for the business name public final TextView mBusinessCategory; //View for the category name public final ImageView businessImage; // View for the business category image Image public final TextView mBusinessDistance; // View for the distance public final CardView card; public ViewHolder(View view) { super(view); mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview); mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview); mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview); businessImage = (ImageView) view.findViewById(R.id.list_item_icon); card = (CardView) view.findViewById(R.id.card_view); } } }
I have developed a light weighted library for android, you can visit https://github.com/ChathuraHettiarachchi/RecycleClick
and follow for following sample
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View v) { // YOUR CODE } });
here is complete code for my custom adapter this code will inflate the rows with list items defined in the xml file named "list_item" it will also perform click event on all list items rows with respective positions.
public class MyCustomAdapter extends RecyclerView.Adapter <
AdapterMyCustomAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener{ public onItemClickListener mListener; public ViewHolder(View v, onItemClickListener listener) { super(v); mListener =listener; v.setOnClickListener(this); } @Override public void onClick(View v) { mListener.onRecyclerItemClick(v, getPosition()); } public static interface onItemClickListener { public void onRecyclerItemClick(View view , int position); } } @Override public int getItemCount() { return 5; } @Override public void onBindViewHolder(ViewHolder holder, int pos) { } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int position) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item, parent, false); /* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/ MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() { @Override public void onRecyclerItemClick(View view, int position) { System.out.println("clicked on list item at position " +position); } }); return vh; }
}
For me the clean way to do that is this one.
-
Adapter constructor
`private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter {
private final EnvironmentTypeRecyclerViewAdapterListener mEnvironmentTypeRecyclerViewAdapterListener; private List<Environment> mEnvironmentsData; public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ViewHolder(View v) { super(v); v.setOnClickListener(this); } @Override public void onClick(View v) { Environment environment = mEnvironmentsData.get(getAdapterPosition()); if (mEnvironmentTypeRecyclerViewAdapterListener != null && environment != null) { mEnvironmentTypeRecyclerViewAdapterListener.onListItemSelected(environment); } } } public EnvironmentTypeRecyclerViewAdapter(List<SmallCellEnvironment> environments, EnvironmentTypeRecyclerViewAdapterListener environmentTypeRecyclerViewAdapterListener) { mEnvironmentTypeRecyclerViewAdapterListener = environmentTypeRecyclerViewAdapterListener; mEnvironmentsData = environments; }`
The Linked Interface
private interface EnvironmentTypeRecyclerViewAdapterListener { void onListItemSelected(Environment environment); }
I'm aware there are a lot of answers, but I thought I might just provide my implementation of it as well. (Full details can be found on another question I answered ).
So, to add a click listener, your inner ViewHolder
class needs to implement View.OnClickListener
. This is because you will set an OnClickListener
to the itemView
parameter of the ViewHolder
's constructor. Let me show you what I mean:
public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView text1, text2; ExampleClickViewHolder(View itemView) { super(itemView); // we do this because we want to check when an item has been clicked: itemView.setOnClickListener(this); // now, like before, we assign our View variables title = (TextView) itemView.findViewById(R.id.text1); subtitle = (TextView) itemView.findViewById(R.id.text2); } @Override public void onClick(View v) { // The user may not set a click listener for list items, in which case our listener // will be null, so we need to check for this if (mOnEntryClickListener != null) { mOnEntryClickListener.onEntryClick(v, getLayoutPosition()); } } }
The only other things you need to add are a custom interface for your Adapter
and a setter method:
private OnEntryClickListener mOnEntryClickListener; public interface OnEntryClickListener { void onEntryClick(View view, int position); } public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) { mOnEntryClickListener = onEntryClickListener; }
So your new, click-supporting Adapter
is complete.
Now, let's use it…
ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects); clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() { @Override public void onEntryClick(View view, int position) { // stuff that will happen when a list item is clicked } });
It's basically how you would set up a normal Adapter
, except that you use your setter method that you created to control what you will do when your user clicks a particular list item.
You can also look through a set of examples I made on this Gist on GitHub:
https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07
you can easily define setOnClickListener in your ViewHolder class as follow :
public class ViewHolder extends RecyclerView.ViewHolder { TextView product_name; ViewHolder(View itemView) { super(itemView); product_name = (TextView) itemView.findViewById(R.id.product_name); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int itemPosition = getLayoutPosition(); Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show(); } }); } }
Mark the class as abstract and implement an OnClick method
public abstract class MainGridAdapter extends RecyclerView.Adapter<MainGridAdapter.ViewHolder> { private List<MainListItem> mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public class ViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView txtHeader; public TextView txtFooter; public ViewHolder(View v) { super(v); txtHeader = (TextView) v.findViewById(R.id.firstLine); txtFooter = (TextView) v.findViewById(R.id.secondLine); } } public void add(int position, MainListItem item) { mDataset.add(position, item); notifyItemInserted(position); } public void remove(MainListItem item) { int position = mDataset.indexOf(item); mDataset.remove(position); notifyItemRemoved(position); } // Provide a suitable constructor (depends on the kind of dataset) public MainGridAdapter(List<MainListItem> myDataset) { mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MainGridAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.list_item_grid_line, parent, false); // set the view's size, margins, paddings and layout parameters ViewHolder vh = new ViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(final ViewHolder holder, final int position) { // - get element from your dataset at this position // - replace the contents of the view with that element OnClickListener clickListener = new OnClickListener() { @Override public void onClick(View v) { onItemClicked(position); } }; holder.itemView.setOnClickListener(clickListener); holder.txtHeader.setOnClickListener(clickListener); holder.txtFooter.setOnClickListener(clickListener); final MainListItem item = mDataset.get(position); holder.txtHeader.setText(item.getTitle()); if (TextUtils.isEmpty(item.getDescription())) { holder.txtFooter.setVisibility(View.GONE); } else { holder.txtFooter.setVisibility(View.VISIBLE); holder.txtFooter.setText(item.getDescription()); } } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.size(); } public abstract void onItemClicked(int position);
}
Implement click handler in binding event to only have one event implementation
Implementation of this:
mAdapter = new MainGridAdapter(listItems) { @Override public void onItemClicked(int position) { showToast("Item Clicked: " + position, ToastPlus.STYLE_INFO); } };
Same can be done for long click
Here is my Code Snippet
v.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int newposition = MainActivity.mRecyclerView.getChildAdapterPosition(v); Intent cardViewIntent = new Intent(c, in.itechvalley.cardviewexample.MainActivityCards.class); cardViewIntent.putExtra("Position", newposition); c.startActivity(cardViewIntent); } });
v
is View from onCreateViewHolder
c
is Context
Here is a strategy that gives a result similar to the ListView
implementation in that you can define the listener in the Activity
or Fragment
level instead of the Adapter
or ViewHolder
level. It also defines some abstract classes that take care of a lot of the boilerplate work of adapters and holders.
Abstract Classes
First, define an abstract Holder
that extends RecyclerView.ViewHolder
and defines a generic data type, T
, used to bind data to the views. The bindViews
method will be implemented by a subclass to map data to the views.
public abstract class Holder<T> extends RecyclerView.ViewHolder { T data; public Holder(View itemView) { super(itemView); } public void bindData(T data){ this.data = data; bindViews(data); } abstract protected void bindViews(T data); }
Also, create an abstract Adapter
that extends RecyclerView.Adapter<Holder<T>>
. This defines 2 of the 3 interface methods, and a subclass will need to implement the last, onViewHolderCreated
method.
public abstract class Adapter<T> extends RecyclerView.Adapter<Holder<T>> { List<T> list = new ArrayList<>(); @Override public void onBindViewHolder(Holder<T> holder, int position) { holder.bindData(list.get(position)); } @Override public int getItemCount() { return list.size(); } public T getItem(int adapterPosition){ return list.get(adapterPosition); } }
Concrete Classes
Now create a new concrete class that extends Holder
. This method only has to define the Views and handle the binding. Here I'm using the ButterKnife library , but feel free to use itemView.findViewById(...)
methods instead.
public class PersonHolder extends Holder<Person>{ @Bind(R.id.firstname) TextView firstname; @Bind(R.id.lastname) TextView lastname; public PersonHolder(View view){ super(view); ButterKnife.bind(this, view); } @Override protected void bindViews(Person person) { firstname.setText(person.firstname); lastname.setText(person.lastname); } }
Finally, in your Activity
or Fragment
class that holds the RecyclerView
you would have this code:
// Create adapter, this happens in parent Activity or Fragment of RecyclerView adapter = new Adapter<Person>(){ @Override public PersonHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.layout_person_view, parent, false); PersonHolder holder = new PersonHolder(v); v.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { int itemPos = holder.getAdapterPosition(); Person person = getItem(itemPos); // do something with person EventBus.getDefault().postSticky(new PersonClickedEvent(itemPos, person)); } }); return holder; } };
Very simple, add this class:
public class OnItemClickListener implements View.OnClickListener { private int position; private OnItemClickCallback onItemClickCallback; public OnItemClickListener(int position, OnItemClickCallback onItemClickCallback) { this.position = position; this.onItemClickCallback = onItemClickCallback; } @Override public void onClick(View view) { onItemClickCallback.onItemClicked(view, position); } public interface OnItemClickCallback { void onItemClicked(View view, int position); } }
Get an instance of 'OnItemClickCallback' interface and put it in your activity or fragment:
private OnItemClickListener.OnItemClickCallback onItemClickCallback = new OnItemClickListener.OnItemClickCallback() { @Override public void onItemClicked(View view, int position) { } };
Then, pass that callback to your recyclerView:
recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(Arrays.asList("1", "2", "3"), onItemClickCallback));
Finally, this would be your adapter:
public class SimpleStringRecyclerViewAdapter extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> { private List<String> mValues; private OnItemClickListener.OnItemClickCallback onItemClickCallback; public SimpleStringRecyclerViewAdapter(List<String> items, OnItemClickListener.OnItemClickCallback onItemClickCallback) { mValues = items; this.onItemClickCallback = onItemClickCallback; } public static class ViewHolder extends RecyclerView.ViewHolder { public final TextView mTextView; public ViewHolder(View view) { super(view); mTextView = (TextView) view.findViewById(R.id.txt_title); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(final ViewHolder holder, final int position) { holder.mTextView.setText(mValues.get(position)); holder.mTextView.setOnClickListener(new OnItemClickListener(position, onItemClickCallback)); } @Override public int getItemCount() { return mValues.size(); } }