RecyclerView onClick

¿Alguien que haya usado RecyclerView encontró una manera de establecer un onClickListener para los elementos en el RecyclerView ? Pensé en configurar un oyente para cada uno de los diseños para cada elemento, pero eso parece un poco complicado. Estoy seguro de que hay una manera para que RecyclerView escuche el evento onClick pero no puedo entenderlo.

Como las API han cambiado radicalmente, no me sorprendería si OnClickListener un OnClickListener para cada elemento. Aunque no es una molestia. En su implementación de RecyclerView.Adapter , debe tener:

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

El método 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(); } 

Esta es una forma mejor y menos estrecha de implementar un OnClickListener para un RecyclerView .

Fragmento de uso:

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

Implementación de 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){} } 

Basado en la respuesta de Jacob Tabak (+1 para él), pude agregar el oyente LongClick:

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

Entonces puedes usarlo así:

 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) { // ... } })); 

Eche un vistazo a una pregunta similar @ comentarios de CommonsWare enlaces a esto , que implementa la interfaz OnClickListener en el viewHolder .

Aquí hay un ejemplo simple de ViewHolder :

  TextView textView;//declare global with in adapter class public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private ViewHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); textView = (TextView)view.findViewById(android.R.id.text1); } @Override public void onClick(View view) { Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show(); //go through each item if you have few items within recycler view if(getLayoutPosition()==0){ //Do whatever you want here }else if(getLayoutPosition()==1){ //Do whatever you want here }else if(getLayoutPosition()==2){ }else if(getLayoutPosition()==3){ }else if(getLayoutPosition()==4){ }else if(getLayoutPosition()==5){ } //or you can use For loop if you have long list of items. Use its length or size of the list as for(int i = 0; i 

El Adapter se ve así:

  @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false); return new ViewHolder(view); } 

Lo hago de esta manera, sin clases indebidas, detectores, etc. Código simple dentro de nuestro adaptador. Solución especialmente mejor para longClick que la presentada anteriormente.

 public class PasswordAdapter extends RecyclerView.Adapter { 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); } } 

Luego, dentro del fragmento o actividad, solo presiona:

 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 = " + position); } }); 

Esto es lo que funcionó para mí. Adjunte OnClickListener a onBindView . Realmente no sé si esto afectará el rendimiento, pero parece funcionar bien con poco código.

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

Esto fue muy difícil para mí tener escucha de clic de elemento en la actividad y también tener escucha de clic para una vista única del elemento que no se activará en el elemento clic oyente. Después de jugar con la respuesta de Jacob Tabak, respeto su respuesta al hacer clic en el elemento si no se presentan otras acciones táctiles dentro del elemento.

Tengo una interfaz OnClickListener personalizada que tiene un evento de clic de elemento que contiene la vista del elemento OnClickListener y la posición del artículo desde el adaptador. Presento una instancia de la misma en el constructor (o puede ser con setter) y la adjunto al listener click listener del contenedor de la vista.

También tengo otro detector de clics en el adaptador (puede estar en el titular de la vista) que manejará el clic de vista actual desde el contenedor.

  public class MyRecyclerAdapter extends RecyclerView.Adapter { private ArrayList mData; private OnItemClickListener mOnItemClickListener; public interface OnItemClickListener { public void onItemClick(View view, int position); } public MyRecyclerAdapter(ArrayList 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(); }} 

En la actividad que necesita para inicializar el adaptador pasando la instancia de 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(), new OnItemClickListener() { @Override public void onItemClick(View view, int position) { ///list item was clicked } }); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(mFeedsAdapter); } 

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

Esto es lo que terminé necesitando, en caso de que alguien lo encuentre útil:

 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:" + getAdapterPosition()); } }); } } 

Fuente: http://blog.csdn.net/jwzhangjie/article/details/36868515

Tengo una buena solución para RecyclerView onItemClickListener para los elementos y subelementos

Paso 1- Crea una interfaz

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

Paso 2- Luego, utilícelo en el método del adaptador en onBindViewHolder de la siguiente manera

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

Paso 3: busca y configura la vista de reciclador en la actividad o el fragmento donde utilizas este

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

Paso 4: Finalmente, implemente la interfaz en la actividad o el fragmento donde está utilizando la herramienta de reciclaje.

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

Aquí esta lo que hice. Esta solución es compatible con onClick y onLongClick tanto en RecyclerView Items como Views inside RecyclerView Items (vistas internas).

Etiqueta tagHolder en las vistas de mi elección:

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

Y uso holder.getPosition () para recuperar la posición en el método onClick () (onLongClick es similar):

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

Una variante con getChildPosition también funciona. Tenga en cuenta que para las vistas internas, en onClick () use:

 int position = recyclerView.getChildPosition((View)view.getParent()); 

En mi opinión, la ventaja de esta solución es que cuando se hace clic en la imagen, solo se llama al oyente de imagen onclick (), mientras que cuando combiné la solución de Jacob para una vista de artículo RecyclerView y mi solución para las vistas internas, la vista de elemento RecyclerView onclick ( ) también se llama (cuando se hace clic en la imagen).

Hay una manera mucho más fácil de hacer esto. Solo solicite al hacer clic en onBindViewHolder en la vista raíz.

Considere que esta es su vista para el adaptador,

    

Luego haz lo siguiente en tu adaptador

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

Puede pasar un clickListener a Adapter .

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

luego pásalo a Adapter :

 MainAdapter mainAdapter = new MainAdapter(this, mItemClick); 

En Adapter ‘s 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; } 

Puede implementar OnClickListener en su clase 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()); } } 

Y onBindViewHolder establece el elemento del titular de su vista

 public void onBindViewHolder(ViewHolder holder, int position) { holder.tvTitle.setText(objects.get(position).getTitle()); holder.item = objects.get(position); } 

Demasiado simple y efectivo.

En lugar de implementar la interfaz View.OnClickListener dentro del titular de la vista o crear una interfaz e implementar la interfaz en su actividad, utilicé este código para simplificar la implementación de OnClickListener .

 public static class SimpleStringRecyclerViewAdapter extends RecyclerView.Adapter { // Your initializations goes here... private List 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 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(); } } 

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

All the answers posted so far are great solutions, however if you do not want to deal with too many implementation details, and just want it to work similarly to how ListView does, I would recommend using TwoWay-View, as seen here:

https://github.com/lucasr/twoway-view

Note that this implementation also supports long press on items, as well as support for pressed states (which is something important that other solutions to this question lack).

If you don’t want to use the entire library, take a look at the ClickItemTouchListener class, which can be used as a standalone if needed. The only issue I found with it at the moment is with long press + scrolling, it seems to have incorrect behaviour.

If you want to catch click event On Individual items then just implement OnClickListener in ViewHolder class and then set click listeners on individual views or whole itemView .

Following example shows the same

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

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

The RecyclerView does not have a OnClickListener and will have to implement it ourselves.

I like to add a OnItemClickListener interface in Adapter with an onClick method invoked when you click on the item view from the ViewHolder . Thus the responsibility of managing the click on an item is outside the ViewHolder and Adapter . Will the activity or fragment which will decide what to do

Add an interface to the listener and the listener object.

 public class ItemsAdapter extends RecyclerView.Adapter { ... private static OnItemClickListener onItemClickListener; ... public static interface OnItemClickListener { public void onItemClick(View view, int position); } ... } 

We capture the click of the root view of the item and when the callback is triggered onClick listener call on the adapter .

 public class ItemsAdapter extends RecyclerView.Adapter { ... 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); } }); } } } 

Since the activity or fragment , fragment in our case , we assign a listener to the adapter and the onClick callback we will get the selected item by position and opened a detailed activity of item.

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

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:

      

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 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 } ... } 

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

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

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 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 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

This is what I do to reuse OnClickListener

  public class TestAdapter extends RecyclerView.Adapter implements View.OnClickListener 

in ViewHoder Take itemlayout’s parent

  public class MyviewHolder extends RecyclerView.ViewHolder { LinearLayout linearLayout_item; public MyviewHolder(View itemView) { super(itemView); linearLayout_item=itemView.findViewById(R.id.linearLayout_item); } } 

in onBindViewHolder set tag as position

  @Override public void onBindViewHolder(MyviewHolder holder, int position) { holder.linearLayout_item.setTag(position); holder.linearLayout_item.setOnClickListener(this); } 

and in Onclick

  @Override public void onClick(View v) { int position = (int) v.getTag(); switch (v.getId()) { case R.id.linearLayout_item: // do some thing with position break; } } 

Mark the class as abstract and implement an OnClick method

 public abstract class MainGridAdapter extends RecyclerView.Adapter { private List 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 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 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> . This defines 2 of the 3 interface methods, and a subclass will need to implement the last, onViewHolderCreated method.

 public abstract class Adapter extends RecyclerView.Adapter> { List list = new ArrayList<>(); @Override public void onBindViewHolder(Holder 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{ @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(){ @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; } };