RecyclerView onClick
Asked Answered
T

49

676

Has anyone using RecyclerView found a way to set an onClickListener to items in the RecyclerView? I thought of setting a listener to each of the layouts for each item but that seems a little too much hassle I'm sure there is a way for the RecyclerView to listen for the onClick event but I can't quite figure it out.

Torse answered 28/6, 2014 at 21:27 Comment(6)
#24885723Unisexual
RecyclerViewDemo I found this project great, using interfaces to provide more free actions.Ferroelectric
check this tutorial wiki.workassis.com/android-recyclerview-exampleDanseur
Simple and easy to use - github.com/rahulkapoor1/ClickableAdapterLinderman
https://mcmap.net/q/49776/-android-recyclerview-vs-listview-with-viewholderDipetalous
Added a Jetpack implementation on the second page, let me know whether we can improve it. Jetpack/AndroidX seems to be the trend lately.Rarebit
M
525

As the API's have radically changed, It wouldn't surprise me if you were to create an OnClickListener for each item. It isn't that much of a hassle though. In your implementation of RecyclerView.Adapter<MyViewHolder>, you should have:

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

The onClick method:

@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();
}
Microspore answered 28/6, 2014 at 22:15 Comment(28)
what if i want to delete a row on its click ?Unskillful
I like this answer better than the one you linked. Who wants to write a gesture listener and hit box detection to handle this. Google--Chesterchesterfield
getChildPosition(view) is deprecated methodSidecar
we can use getChildLayoutPosition(view) instead.Sidecar
getChildAdapterPosition(view) is a more reliable option than getChildLayoutPosition(view) getChildLayoutPosition(view) may not be equal to Item's adapter position if there are pending changes in the adapter which have not been reflected to the layout yet.Attenuation
Do you mind telling which classes are your snippets in? onClick(), belonging to OnClickListener can be attached to ANY View. The whole question here is which! Please make an effort, a method is not only identified by a name, but also at least by a class. If you don't say your code is to be added to the adapter, your answer does not really help.Uvulitis
Should the onClick method be in the fragment that holds the RecyclerView ? Because you reference the mRecyclerView in your MyOnClickListener class. Where did you get the reference to that object ?Mindamindanao
getChildPosition is now deprecated, please see my answer below and gist.github.com/RTimal/ddf4040cfba28b461ec7Allpowerful
+1 for the fact that you specifically pointed out another author's method is less tightly coupled, and linked to it as the first line of your answer.Cenogenesis
getChildPosition(View) is deprecated. Use public int getChildAdapterPosition (View child) instead. Full documentation hereVestpocket
getChildPosition is deprecated getChildAdapterPosition will give wrong position when you scroll the view. getChildLayoutPosition will give correct position.Desiccant
Where MyOnClickListener class should be written?Justness
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int position) is confusing. The second argument is viewType instead of position. The position argument is only available in onBindViewHolder(MyViewHolder holder, int position)Futuristic
RecyclerView is pretty powerful even though you have to do the legwork yourself to handle the data and deal with any changes. +1 for the answer, perfecto!Splashboard
How to send mRecyclerView in an adapter ?Dogeatdog
it's bad practice to implement click listener inside an onCreateView().Dilettantism
Binding the click listener during ViewHolder creation is the correct way as it avoids repeated listener assignments that would happen if you did it in onBindViewHolder. However, the trick being missed here is that I also use ViewHolder to retain an ID (or some other 'handle' metadata) that provides means to determine the clicked item. This is instead of all the pointless jumping through hoops to calculate clicked Item position. So all I do is bind a click listener in the holder ctor, and have the holder also capture meta information that provides a pointer of some sort to the underlying data.Penetrant
I find it absolutely staggering that despite this being so simple to do as described above, some of the highest voted answers here advocate use of MotionEvents and various other bloat.Penetrant
where do this 'onClick' method belongs? How did you get 'mRecyclerView' inside that onClick method?Closemouthed
what if the list has one item ? :/ i need recycler view click not item clickAppeasement
@Microspore can you help me to solve this #50115752Reimer
where does this 'onClick' method belong? How did you get 'mRecyclerView' inside that onClick method?...Cliquish
@PembaTamang @Shirish Herwade You can override the method onAttachedToRecyclerView() of your adapter, then you will get a reference to the recyclerView; set it to a member variable say mRecyclerView. And now, you got it.Philter
why is it so confusing to just add a listener =.='' it's so much easier on iOS... Adding delegateFairspoken
that mRecyclerView was bothering me (how do you access it inside adapter-class), so I modified the Adapter constructor Adapter(..., RecyclerView rcv) to accept the owner RV. Then I am able to access the element's position [inside onClick] final int pos = myAdapter.this.myRecView.getChildAdapterPosition(view); and it seems to work...Whitesmith
Hi mate, can you help me to solve this issue please.. I've been stuck many days here #57068821Streaky
@Sa'adAbdurrazzaq No, and I'd appreciate it if you wouldn't ping people like this.Microspore
Because MANY people asked this: If I understand correctly, the onClick() method is inside the class "MyOnClickListener" he used for the click listener. The reference to mRecyclerView must have been passed as an argument to the constructor or so (which he unfortunately didn't show). please correct me if I'm wrong!Beverie
O
656

Here is a better and less tightly coupled way to implement an OnClickListener for a RecyclerView.

Snippet of usage:

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

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){}
}
Onomatopoeia answered 4/10, 2014 at 20:22 Comment(32)
This will not provide any clue about which button or view (within the item) was clicked. But for overall item click, this is fine.Latinalatinate
what if i want to delete a row on its click ?Unskillful
You should have no issue deleting a row on click. The OnItemClickListener gives you the position of the view in the adapter so you can delete it.Onomatopoeia
ngen's comment is correct - if you want to attach an onClick listener to a specific item within the item view, you should probably do that in your adapter, in onBindViewHolder, or in your viewholder itself.Onomatopoeia
One problem with this method is when you are doing something that takes a few hundred milliseconds like starting an activity. When the item is clicked, and it has a clicked animation there is a noticeable delay between clicking and seeing the animation.Trichome
Can someone please explain the role of mGestureDetector.onTouchEvent(e) here and how it helps in determining the click?Elston
This solution feels extremely clunky, there's some delay when processing the 'click' and the feel isn't just okSeemly
Why is your code in OnInterceptTouchEvent instead of OnTouchEvent?Ousley
Sorry, how do I use the setItemChecked(position) with your implementation?Vindicate
@JacobTabak can we handle both click on individual views in adapter and item click listener. The touch is intercepted by onTouchListener. If i have both then i have both fire listeners one on view and the other on the row itemRoguish
@JacobTabak Note: view.getChildPosition(childView) is deprecated nowSchroder
@JacobTabak currently i add a method onLongPress(MotionEvent e) in the interface & in the GestureDetector i override onLogpress. (@Override public void onLongPress(MotionEvent e) { listener.onLongPress(e); }) i want to pass the child view and position , not the motion event to the listener like onItemClick.... How can i implement that..Scheffler
Could anyone explain to me why this solution with the GestureDetector is supposed to be a better solution than just using "setOnClickListener" inside of onBindViewHolder() in the adapter to the according element? This way at least I need less code than with the GestureDetector solution. Thanks for an explanation.Umbrageous
What do I use instead of view.getChildPosition as it has been depreciated?Bracelet
Simply use interfaces to avoid complexity. See gist.github.com/riyazMuhammad/1c7b1f9fa3065aa5a46fFreiman
I just found out that this approach raises a fatal performance issue. There's great delay before the user could scroll the list(considering a list of several items). The user has to hold for sometime before scrolling in order for the RecyclerView to scroll, otherwise, it's just responding to the tough events.Exodontist
getChildPosition is now deprecated and this does not tell you which view was clicked. Please see my answer below and gist.github.com/RTimal/ddf4040cfba28b461ec7Allpowerful
this method will not show the click effect on that item. Please follow below link plus.google.com/+AnjulaSashika/posts/D9jtomxRyDrCloudscape
You should also override onRequestDisallowInterceptTouchEvent event.Herrera
For some reason it doesn't return a clicked view. In my case I click on a checkbox but given view is something different. The way I check: view.getId() == R.id.selectionAstridastride
I figured out the view is a topmost Layout for a list_item.xml. How can I know on which exactly view a click was?Astridastride
getChildPosition() method is deprecated. Use getChildAdapterPosition(View) or getChildLayoutPosition(View).Tortuous
@JacobTabak why this method is better than attaching onClickListener on individual Items ??Hoover
This implementation introduces a few awkward edge cases since the touch events are divorced from the view they represent. Among them is click timing. GestureDetector supports long press by default, so a longer click is consumed and never reported—long press should be shut off. Another is the requirement of setting the view's visual clickability separately. This implementation doesn't connect with enabling the view to show this state to the user.Zohar
Why are you taking a Context as a constructor parameter when you can just use recyclerView.getContext()?Catenane
Another reason to avoid the Gesture Detector solution is that it doesn't work with keypad navigation.Bezonian
I have a checkbox in the card and when I use this class, for some reason holder.checkbox.setOnCheckedChangeListener does not get called. How to sort of bring the checkbox "to front"?Avast
This solution does not consider focus navigation (keyboard navigation), something that a simple click listener could solve (click listeners encapsulates keyboard enter, D-Pad center, and other pointer events). This solution is not accessible as it can only handle touch events and shouldn't be used. Consider using a simple click listener with getChildAdapterPosition() to retrieve position.Candicecandid
When user click on button which is inside item view, how to handle that event?Ingamar
doesnt work on a list with one item. its item click rather than recycler click.Appeasement
This worked for me. Easier to understand for newbie like me. :) Thanks.Macmacabre
You don't need a GestureDetector to handle clicks in a RecyclerView. You just need setOnClickListener. Why is this the most upvoted answer???Shearwater
M
525

As the API's have radically changed, It wouldn't surprise me if you were to create an OnClickListener for each item. It isn't that much of a hassle though. In your implementation of RecyclerView.Adapter<MyViewHolder>, you should have:

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

The onClick method:

@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();
}
Microspore answered 28/6, 2014 at 22:15 Comment(28)
what if i want to delete a row on its click ?Unskillful
I like this answer better than the one you linked. Who wants to write a gesture listener and hit box detection to handle this. Google--Chesterchesterfield
getChildPosition(view) is deprecated methodSidecar
we can use getChildLayoutPosition(view) instead.Sidecar
getChildAdapterPosition(view) is a more reliable option than getChildLayoutPosition(view) getChildLayoutPosition(view) may not be equal to Item's adapter position if there are pending changes in the adapter which have not been reflected to the layout yet.Attenuation
Do you mind telling which classes are your snippets in? onClick(), belonging to OnClickListener can be attached to ANY View. The whole question here is which! Please make an effort, a method is not only identified by a name, but also at least by a class. If you don't say your code is to be added to the adapter, your answer does not really help.Uvulitis
Should the onClick method be in the fragment that holds the RecyclerView ? Because you reference the mRecyclerView in your MyOnClickListener class. Where did you get the reference to that object ?Mindamindanao
getChildPosition is now deprecated, please see my answer below and gist.github.com/RTimal/ddf4040cfba28b461ec7Allpowerful
+1 for the fact that you specifically pointed out another author's method is less tightly coupled, and linked to it as the first line of your answer.Cenogenesis
getChildPosition(View) is deprecated. Use public int getChildAdapterPosition (View child) instead. Full documentation hereVestpocket
getChildPosition is deprecated getChildAdapterPosition will give wrong position when you scroll the view. getChildLayoutPosition will give correct position.Desiccant
Where MyOnClickListener class should be written?Justness
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int position) is confusing. The second argument is viewType instead of position. The position argument is only available in onBindViewHolder(MyViewHolder holder, int position)Futuristic
RecyclerView is pretty powerful even though you have to do the legwork yourself to handle the data and deal with any changes. +1 for the answer, perfecto!Splashboard
How to send mRecyclerView in an adapter ?Dogeatdog
it's bad practice to implement click listener inside an onCreateView().Dilettantism
Binding the click listener during ViewHolder creation is the correct way as it avoids repeated listener assignments that would happen if you did it in onBindViewHolder. However, the trick being missed here is that I also use ViewHolder to retain an ID (or some other 'handle' metadata) that provides means to determine the clicked item. This is instead of all the pointless jumping through hoops to calculate clicked Item position. So all I do is bind a click listener in the holder ctor, and have the holder also capture meta information that provides a pointer of some sort to the underlying data.Penetrant
I find it absolutely staggering that despite this being so simple to do as described above, some of the highest voted answers here advocate use of MotionEvents and various other bloat.Penetrant
where do this 'onClick' method belongs? How did you get 'mRecyclerView' inside that onClick method?Closemouthed
what if the list has one item ? :/ i need recycler view click not item clickAppeasement
@Microspore can you help me to solve this #50115752Reimer
where does this 'onClick' method belong? How did you get 'mRecyclerView' inside that onClick method?...Cliquish
@PembaTamang @Shirish Herwade You can override the method onAttachedToRecyclerView() of your adapter, then you will get a reference to the recyclerView; set it to a member variable say mRecyclerView. And now, you got it.Philter
why is it so confusing to just add a listener =.='' it's so much easier on iOS... Adding delegateFairspoken
that mRecyclerView was bothering me (how do you access it inside adapter-class), so I modified the Adapter constructor Adapter(..., RecyclerView rcv) to accept the owner RV. Then I am able to access the element's position [inside onClick] final int pos = myAdapter.this.myRecView.getChildAdapterPosition(view); and it seems to work...Whitesmith
Hi mate, can you help me to solve this issue please.. I've been stuck many days here #57068821Streaky
@Sa'adAbdurrazzaq No, and I'd appreciate it if you wouldn't ping people like this.Microspore
Because MANY people asked this: If I understand correctly, the onClick() method is inside the class "MyOnClickListener" he used for the click listener. The reference to mRecyclerView must have been passed as an argument to the constructor or so (which he unfortunately didn't show). please correct me if I'm wrong!Beverie
S
130

I do it in this way, without undue classes, detectors etc. Simple code inside our adapter. Especially better solution for longClick than presented before.

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private final ClickListener clickListener;

    public PasswordAdapter(ClickListener clickListener) {
         this.clickListener = clickListener;
    }

    public 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) {
            int position = getBindingAdapterPosition();
            if (position >= 0) {
                clickListener.onItemClick(position, v);
            }
        }

        @Override
        public boolean onLongClick(View v) {
            int position = getBindingAdapterPosition();
            if (position >= 0) { 
                clickListener.onItemLongClick(position, v);
                return true;
            }
            return false;
        }
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Then inside fragment or activity, just hit:

PasswordAdapter mAdapter = new PasswordAdapter(
    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);
        }
    }
);
Selfindulgent answered 28/7, 2015 at 8:38 Comment(12)
instead of OurAdapter.clickListener i think Marurban means PasswordAdapter.clickListener and instead of TrainingAdapter.ClickListener(), should be PasswordAdapter.ClickListener(). Other than that, great solution Marurban! worked for meSpeed
onItemClick listener is also being activated on long click.Aby
I had to use v.setClickListener(this) in ViewHolder constructor to make it work. But longclicklistener is still not workingCharliecharline
ViewHolder must be static for the best performance. this is not a good answer.Slipon
In the ViewHolder Class, when I set the onLongClick to return false, I fire off a longclick and both onItemClick and onItemLongClick get called. When I set the onLongClick to return true, only the correct click gets called, but the adapter doesnt update the recyclerview when I delete an item on a long click. Any Ideas as to what I'm doing wrong?Feathers
The static clickListener creates a memory leak. Declare the listener as non-static and bind it to the ViewHolder instead.Bezonian
return true from onLongClick to consume the event and avoid toast appearing for both click and long click.Togetherness
Can you let me know if I had 2 buttons How can I get to know which button is clicked inside the Recyclerview?Incredible
You can check its id inside onClick method v.getId()Selfindulgent
@Bezonian Can you provide an example of how best to bind the clickListener to the ViewHolder? Just assign it to the itemView of the clickListener?Killdeer
@Killdeer The simplest way is to initialize the listener early and pass it as argument to the Adapter constructor and then the ViewHolder constructor.Bezonian
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
B
102

Check out a similar question @CommonsWare's comment links to this, which implements the OnClickListener interface in the viewHolder.

Here's a simple example of the ViewHolder:

/** Declare global with in adapter class. */
TextView textView;

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 RecyclerView. */
        if (getLayoutPosition() == 0) {
           // Do whatever you want here
        } else if(getLayoutPosition() == 1) { 
           // Do whatever you want here
        } else if(getLayoutPosition() == 2) {
           // Do whatever you want here
        }

        /** Or you can use For loop if you have long list of items. */
        for (int i = 0; i < exampleList.size(); i++) {
            // Do whatever you want here
        }
    }
}

The creation of ViewHolder inside your RecyclerView.Adapter then looks like this:

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext())
    View view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
    return new ViewHolder(view);
}
Byelaw answered 14/7, 2014 at 21:37 Comment(7)
This seems to go the wrong direction though. If you need to re-use a recyclerview in another fragment/activity, the adapter/viewholder are now defining the logic of the clicks instead of whatever is containing them. The clicks should really be handled directly or indirectly by the containing instance. It seems that a touch listener is the only effective way to go about this.Multiple
@tencent I don't see how that is the problem. If the ViewHolder itself contains all information in regards to what data is selected when the element itself is clicked, then the only responsibility of the container is the display of N elements, rather than that of handling the selection of a specific i-th element out of the N elements. The ListView was already problematic if you had to create a list of more complicated objects than just simple rows. What if you need to handle different events depending on where you click the item in the ListView? You're screwed. Here, you have each listeners.Shearwater
I agree with @Shearwater on this one. I also came to upvote this answer after reading the section of Commonsware's book on handling clicks in RecyclerViews It has worked great for me so far.Thirteenth
The whole point of a view holder is for it to hold the references to containing elements. If you use findViewById in onCreateViewHolder you're working around the intentional pattern.Overdose
findViewById is only being used on view holder creation here (hence onCreateViewHolder). The view holder is intended to prevent finding the view every time an item is bound to the holder, not on initial creation.Hygienic
getPosition() is deprecated, use getAdapterPosition() or getLayoutPosition() instead.Lindemann
Setting click for any part of view in RecyclerView.ViewHolder leads to incorrect processing of touch events. For example, if you would like to implement SnapHelper for such RecyclerView, OnClickListener will override OnTouchListener in SnapHelper and last one won't receive MotionEvent.ACTION_DOWN events.Ourselves
C
97

Based on Jacob Tabak's answer (+1 for him), I was able to add onLongClick listener:

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

Then you can use it like this:

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) {
        // ...
    }
}));
Carlson answered 9/11, 2014 at 9:9 Comment(7)
Took me a while to adapt to my app, and align and format code to Java/Android standards, but eventually it worked fine.Klee
How do you add an animation for the long click?Vicinage
@Carlson click effect is not working by using this, although if we set click listener in adapter click effect works any solution to thisArgot
You should also override public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}Underpay
For some reason it doesn't return a clicked view. In my case I click on a checkbox but given view is something different. The way I check: view.getId() == R.id.selectionAstridastride
I figured out the view is a topmost Layout for a list_item.xml. How can I know on which exactly view a click was?Astridastride
getChildPosition() method is deprecated. Use getChildAdapterPosition(View) or getChildLayoutPosition(View).Tortuous
C
73

This is what worked for me. Attach the OnClickListener to the onBindView. I don't really know if this will impact the performance, but it seems to work fine with little code.

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();
            }
    });
}
Champerty answered 2/11, 2014 at 16:6 Comment(10)
in my case holder.itemView.setOnClickListener(..)Skyline
it is named 'itemView' instead of 'view' in my case, just saying for the beginners, some of them dont understand what are they copying, and can't figure out why doesnt workSkyline
Question: The onBindViewHolder(...) returns an int position. Which position is this in regards to the RecyclerView? Is it the Layout Position or Adapter Position?Exodontist
Its the layout positionChamperty
for me this seem to only apply for the last visible item not the clicked itemException
This solution seems the best for me, but how does this differ from @Byelaw 's answer in therms of performance? He has implemented View.OnClickListener directly on the ViewHolder class, which than spits out the onClick method separately. Which would be the best solution?Carborundum
This unnecessarily creates a new OnClickListener constantly while scrolling and thus shouldn't be used. Use getAdapterPosition() to access the item position from the click listener.Schutz
@Schutz where do you do this.Champerty
@orignMaster ViewHolder has that method, so it can be used in any listener there.Schutz
Total disaster. You'll get the item clicked position of the item which was just blinded not the item you clickWeihs
A
55

This was so hard for me to have on item click listener in the activity and also to have click listener for single view of the item that will not trigger on item click listener. After playing around with Jacob Tabak's answer I respect his answer for on item click if no other touch actions inside item are presented.

I have a custom OnClickListener interface that have on item click event which holds the clicked item's view and the item position from the adapter. I present an instance of it in the constructor(or it can be with setter) and attach it to the view holder container click listener.

I also have other click listener in the Adapter(Can be in the view holder) which will handle current View click from the container.

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

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
        }
    });

    viewHоlder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do button click work here with
            // mData.get( viewHolder.getAdapterPosition() );
        }
    });

    return viewHolder;
}

@Override
public int getItemCount() {
    return mData.size();
}}

In the activity you need to initialize the adapter by passing instance of the 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);
}

And my 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);
}}
Auriol answered 3/2, 2015 at 16:42 Comment(14)
This approach worked well for me - it means you can handle clicks in the activity rather than inside the grid viewMamey
Where can I give you money. 4 hours of searching and then I read your post. Thanks for the time you took to post this.Acceptable
This sounds stupid but, does this have any memory or efficiency like issue? Because we are assigning the click listener every time a view is being drawn right?Chough
@Raghav yes every time view is being bind a new click listener is assigned, but this is the standard flow. But the mOnItemClickListener is created only once for the adapter just the view and its position are different on each item click ;)Auriol
Thanks, this really helped me understand how to implement OnClickListener InterfacesLeastways
container should be WeakReference<View>. The Context (your activity) contains a reference to the recycler view, which contains a reference to the view holder which, in this case, has a reference back to the context.Lipson
@Lipson the container is different for each item and is needed to assign the onclick listener to it. The RecyclerView should recycle the ViewHolder if it's needed...Auriol
Great example to kill app performance and create memory overuse! With this example you just need scroll to create hundreds of useless objects, that in a moment will be useless and have to be accessed as garbige. @NoobDogg is right. No ClickListeners haven't to be created at onBindView. A click listener have to be created once in onCreateView (or holder constructor), and exists while we need screen with this adapter.Laniary
@MykolaTychyna how will you perform click listener for an item, when you don't have it's position on onCreateView?! You need to know which item was clicked and have it's position so you can access it's data. You are just not rightAuriol
@Sir NIkolay Cesar The First please at first notice the problem of creation of huge numbers of objects (ClickListeners) with very short life time. Its overhead and antipattern - always! When you are running onCreateViewHolder your are running ViewHolder constructor, and inside it you have to create click lstener. Inside of method onClick you can call getAdapterPosition and perform with this index get on your data collection. In this case ClickListeners will be created as much as ViewHolders.Laniary
To get the item position inside onCreateView (so that the click listener may be bound there), you simply need to have another property inside your ViewHolder that captures the index, or some other metadata that provides a 'handle' to that item, during onBindViewHolder. This is all I do. There is no need for repeated binding of listeners, and there is no need to jump through any hoops to calculate the clicked item. I'm absolutely staggered that none of these answers illustrate this.Penetrant
How to pass the holder values through intent?Dunbarton
Ok I editted my answer as I see that some people are still liking it ;)Auriol
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
H
43

This is what I ended up needing, in case someone finds it useful:

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

    }
}

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

Hamlett answered 24/7, 2014 at 10:36 Comment(5)
Of all the versions I tried, this is the one I got working. But is it ok, to do it that way? Or is there a better way, like best practice?Squarely
As far as I could tell, this was the only way. Check this out for more details! https://mcmap.net/q/49516/-why-doesn-39-t-recyclerview-have-onitemclicklistenerHamlett
How can i open new fragment from inside onclick method?Huei
getAdapterPosition() replaces getPosition()Swanger
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
C
41

I have nice solution for RecyclerView's onItemClickListener for the items and subitems

Step 1- Create an interface

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

Step 2- Then use it in adapter's onBindViewHolder method in the following way

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

Step 3- find and setup recycler view in activity or fragment where you are using this

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

Step 4- Finally implement interface in activity or fragment where you are using the 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();
        }
    }

Update for Kotlin Language I have updated the code for kotlin in which only whole view has on click listener. You can set subitems click listener by editing interface and code according to above java code.

Adapter

class RecentPostsAdapter(private val list: MutableList<Post>) :
    RecyclerView.Adapter<RecentPostsAdapter.ViewHolder>() {
    private lateinit var onItemClickListener: OnItemClickListener

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.listitem_recent_post, parent, false)
        )
    }

    override fun getItemCount(): Int {
        return list.size
    }

    fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
        this.onItemClickListener = onItemClickListener
    }

    private fun getItem(position: Int): Post {
        return list[position]
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
        holder.itemView.setOnClickListener(View.OnClickListener {
            onItemClickListener.onItemClick(
                position
            )
        })
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private var imageView: NetworkImageView? = null
        private var tvTitle: TextView? = null
        private var tvExcerpt: TextView? = null
        private var htmlSpanner: HtmlSpanner = HtmlSpanner()

        init {
            imageView = itemView.findViewById(R.id.niv_post_image)
            tvTitle = itemView.findViewById(R.id.tv_post_title)
            tvExcerpt = itemView.findViewById(R.id.tv_post_excerpt)
        }

        fun bind(post: Post) {
            tvTitle?.text = post.title
            tvExcerpt?.text = htmlSpanner.fromHtml(post.excerpt)
        }
    }

    interface OnItemClickListener {
        fun onItemClick(position: Int)
    }
}

Activity or Fragment

recyclerView = view.findViewById(R.id.rvHomeRecentPosts)
        recyclerView.layoutManager = LinearLayoutManager(view.context)
        list = mutableListOf()
        recentPostsAdapter = RecentPostsAdapter(list)
        recyclerView.adapter = recentPostsAdapter
        recentPostsAdapter.setOnItemClickListener(object:RecentPostsAdapter.OnItemClickListener{
            override fun onItemClick(position: Int) {
                (activity as MainActivity).findNavController(R.id.nav_host_fragment).navigate(R.id.action_nav_home_to_nav_post_detail)
            }

        })
Cushing answered 9/10, 2015 at 7:3 Comment(5)
This is the best solution because we usually need a lot of properties from activity/fragment on our onItemClickListener, and theres no sense to call it direct from the viewholder (i would have to create a custom constructor for each adapter). By the way, your code is a little extense, i suggest you to cut it to the most important part (setOnItemClickListener).Wampum
this is a good simple approach for differentiating the row / item from the sub-itemsRompish
I'm listened that it is bad solution because you create too many listeners.Parts
It will create as many listeners as many items are visible on the screen. As we scroll the unused listeners will be garbage collectedCushing
Other way is to add a tag to the view, we can use the position number as tag and create only one listener and set it to all items. Then the position will be found out by getting the tagCushing
D
17

Here is what I did. This solution supports both onClick and onLongClick on both RecyclerView Items and Views insides RecyclerView Items (internal views).

I tag viewHolder on the views of my choice :

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

And I use holder.getPosition() to retrieve the position in onClick() method (onLongClick is 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();
    }
}

A variant with getChildPosition also works. Please note that for the internal views, in onClick() use :

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

To my mind, the avantage of this solution is that when one clicks on the image, only the onclick() image listener is called whereas when I combined Jacob's solution for a RecyclerView Item view and my solution for internal views the RecyclerView Item view onclick() is also called (when click on image).

Dagan answered 14/11, 2014 at 23:56 Comment(1)
There are some other ways to get a reference to the full list row View, using the ViewHolder: 1 - ViewGroup rowView = (ViewGroup)viewHolder.imageIV.getParent(). 2 - View rowView = viewHolder.itemView. Then you can add onClickListeners to these rowViews.Convolvulus
R
9

There is far easier way to do this. Just apply on click in onBindViewHolder on root view.

Consider this is your view for adapter,

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

Then do following in your adapter

//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);
    }
}
Raleighraley answered 29/6, 2016 at 5:17 Comment(0)
D
8

You can pass a clickListener to Adapter.

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

then pass it to Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

In 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;
}
Declinate answered 3/6, 2015 at 6:21 Comment(1)
How do you pass the holder values through intent?Dunbarton
F
8

Way too simple and effective.

Instead of implementing interface View.OnClickListener inside view holder or creating and interface and implementing interface in your activity - I used this code for simple on OnClickListener implementation.

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();
        }
    }
Freeload answered 7/10, 2015 at 6:48 Comment(1)
This is a common bad practice because it looks way too easy. You are creating a new inner listener each time an object is binded (and each item in a recycler can be bound lots of times) which is bad for a)performance b)garbage collection. Instead you should create ONE listener somewhere (in the viewholder, in the adapter, in the upper fragment or activity) and just add it to the items in the viewholder constructor on in onCreateViewHolder. This has the added complexity of having to figure out which item was clicker, but can be solved easily via tags or adding more info to the holder.Jural
V
7

You can implement View.OnClickListener to your ViewHolder class

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

And onBindViewHolder set your view holder's item:

public void onBindViewHolder(ViewHolder holder, int position) {
    holder.tvTitle.setText(objects.get(position).getTitle());
    holder.item = objects.get(position);
}
Vesica answered 30/12, 2014 at 20:22 Comment(0)
I
7

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

    }
} 
Inferential answered 31/12, 2014 at 7:25 Comment(0)
T
7

I have developed a light weighted library for android, you can visit github and follow this sample:

RecycleClick.addTo(YOUR_RECYCLE_VIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
    @Override
    public void onItemClicked(RecyclerView recyclerView, int position, View v) {
        // Your code here
    }
});
Tilth answered 3/2, 2017 at 7:30 Comment(1)
Can confirm, this library is great! Very easy to use, good job!Adulterine
Z
7

According to Yigit Boyar, the best way to register a click on a RecyclerView is to define the click in the creation of the ViewHolder instead of just creating a new onClickListener for each item that the onBindViewHolder binds

Example:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
   val itemBinding = LayoutInflater.from(context).inflate(R.layout.my_layout, parent, false)

   val vh = MainViewHolder (itemBinding)
   vh.itemView.setOnClickListener {
       val pos = vh.adapterPosition
       if(pos != NO_POSITION){
           itemClickLister.onCocktailClick(myList[pos],pos)
       }
   }

   return vh
}
Zebrawood answered 15/8, 2020 at 22:13 Comment(2)
Whats no position?Eugeniusz
it's -1, its part of RecyclerView developer.android.com/reference/android/support/v7/widget/…Astylar
D
6

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.

Due answered 27/10, 2014 at 22:5 Comment(0)
C
6

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();
            }
        });
    }
}
Cd answered 29/3, 2017 at 21:33 Comment(0)
K
5

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
    }
  ...
}
Karisakarissa answered 24/10, 2014 at 17:55 Comment(1)
getChildPosition() is decapitatedException
H
5

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<ItemsAdapter.ViewHolder> {

  ...

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

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
            }
        });
        ...
    }
...
}
Hermanhermann answered 21/5, 2015 at 19:12 Comment(1)
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
F
5

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.getAdapterPosition());
        }
    });
    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);
    }
 }
}
Freiman answered 22/7, 2015 at 12:3 Comment(1)
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
W
4

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

    }
}
}
Waadt answered 8/8, 2015 at 22:46 Comment(0)
U
4

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

Under answered 11/8, 2015 at 12:3 Comment(1)
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
P
4

Kotlin implementation of nhaarman's answer :

mRecyclerView.addOnItemTouchListener(object  : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
            override fun onItemClick(view: View, position: Int) {

            }

            override fun onLongItemClick(view: View?, position: Int) {

            }
}){})

RecyclerItemClickListener.java :

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View


open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {

    private var mGestureDetector: GestureDetector

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)

        fun onLongItemClick(view: View?, position: Int)
    }

    init {
        mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent): Boolean {
                return true
            }

            override fun onLongPress(e: MotionEvent) {
                val child = recyclerView.findChildViewUnder(e.x, e.y)
                if (child != null && mListener != null) {
                    mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
                }
            }
        })
    }

    override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
        val childView = view.findChildViewUnder(e.x, e.y)
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
            return true
        }
        return false
    }

    override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
Pritchard answered 31/7, 2018 at 7:54 Comment(2)
Thanks, that is even better than the initial answer. Works fine for meOden
You don't need touch event detection for a recyclerview click, just use setOnClickListener on the viewShearwater
C
4

Here is simple and clear way is add inside your ReacyclerView ViewHolder

public static class MyViewholder extends RecyclerView.ViewHolder {

    public MyViewholder(View itemView) {
        super(itemView);

        itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("Tag", "onClick:" + getAdapterPosition());
            }
        });

    }
}

getAdapterPosition() is returns the current clicked item position

Contrariwise answered 10/6, 2019 at 5:28 Comment(1)
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
R
4

Don't reinvent the wheel! The code for this specific use case is included in the Master/Detail Flow starter project that comes with Android Studio.

From Android Studio select:

  1. File > New > New Project....
  2. In the Phone and Tablet tab select Master/Detail Flow as shown below.

enter image description here

  1. Create the project as either Kotlin or Java.
  2. Profit.

I am not going to include here the code from google's ootb the demo project, but I'll outline the main design approaches in the sample provided by google:

  • the item OnClickListener is created ONLY ONCE, and is assigned to a field in your RecyclerView.Adapter implementation.
  • in the onBindViewHolder() you should set the same, pre-created onClickListener object on your ViewHolder instance with holder.itemView.setOnClickListener(mOnClickListener) (AVOID creating a new instance on every method call!); if you need to capture clicks on some specific elements inside the ViewHolder then extend ViewHolder and expose the elements you need as fields so that you can attach whatever listeners you need in onBindViewHolder() — and once again, do NOT re-create the listeners on every method call — initialise them as instance fields and attach them as needed.
  • you can use .setTag() in order to pass state to your viewHolder, e.g. holder.itemView.setTag(mValues.get(position)); as used in the demo.
Ruffina answered 19/4, 2020 at 21:0 Comment(2)
This is great. Thanks for bringing it to my attention - I normally trust most practices that come directly from Google. Do you know if the approach is any different when using an MVVM architecture? Also, it appears to be called a Primary/Detail Flow now when creating a new project!Oft
I gave it a whirl, and it doesn't seem to cause any issue with my MVVM architected app. I use an ItemViewModel as the .tag object of the item view. Not sure if this is best practice but works for me for now.Oft
G
3

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;
    }
}
Gritty answered 3/12, 2014 at 11:41 Comment(0)
A
3

We can do this using Java weak references. Semantically, the view holder is the one that should respond to the click event or delegate it to the correct responder.

Our goals:

  1. The Viewholder should know nothing about the the class thats responding to the events except that it implements a certain interface.
  2. The click handler should get the position in the RecyclerView of the view thats clicked.
  3. We should be able to discern which view was clicked in the view holder.
  4. Maintain loose coupling between all components and don't cause any retain cycles.

Steps:

  1. Create an interface to handle click responses.

  2. Implement this interface in the Activity that will handle the click.

  3. Add a member variable in the RecyclerView Adapter to hold the Weak Reference and a constructor that sets it.

  4. Do the same in the RecyclerView ViewHolder and add a member variable to keep track of position.

  5. Set your on click listeners on any view you'd like in the ViewHolder, then callback to the responder to handle them.

  6. Change your onBindViewHolder method to set the position when binding.

  7. Pass the responder down to the ViewHolder.

  8. In the responder, you can now use getId() on the view to figure out which view was clicked.

And here's a Gist so you can see how it all fits together: RecyclerView click handling

Allpowerful answered 5/9, 2015 at 8:19 Comment(0)
B
3

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

Bushweller answered 15/6, 2016 at 21:50 Comment(1)
You should use getAdapterPosition() instead of getLayoutPosition()Bezonian
B
3

Setup click listener inside your ViewHolder this way:

public class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView title, year, genre;

    public MyViewHolder(View view) {
        super(view);

        title = (TextView) view.findViewById(R.id.title);
        genre = (TextView) view.findViewById(R.id.genre);
        year = (TextView) view.findViewById(R.id.year);

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}
Balboa answered 22/11, 2018 at 9:37 Comment(2)
getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"Reathareave
using getBindingAdapterPosition() is correct. Make sure you only handle the click if adapterPosition >= 0Shearwater
A
2

For me the clean way to do that is this one.

Adapter constructor

private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter<EnvironmentTypeRecyclerViewAdapter.ViewHolder>
{
     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);
}
Ancon answered 11/3, 2016 at 10:1 Comment(0)
Z
2

This is what I do to reuse View.OnClickListener:

public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyviewHolder>
    implements View.OnClickListener

In ViewHoder take parent view of item layout:

public class MyviewHolder extends RecyclerView.ViewHolder {

    LinearLayout linearLayout;

    public MyviewHolder(View itemView) {
        super(itemView);
        linearLayout = itemView.findViewById(R.id.linear_layout_item);
    }
}

In onBindViewHolder set tag as position:

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

And inside your onClick realization:

@Override
public void onClick(View v) {
    int position = (int) v.getTag();

    switch (v.getId()) {
        case R.id.linear_layout_item:
            // do some thing with position 
            break;
    }
}
Zwart answered 9/3, 2018 at 13:4 Comment(0)
C
2

In kotlin with constructor implementation

Initialize your RecyclerView constructor like below:

class ListAdapter(
    c: Context,
    private var list: List<Project>,
    private val itemClick: (Project) -> Unit
) : RecyclerView.Adapter<ListAdapter.ViewHolder>() 

return with itemClick in your onCreateViewHolder:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):ProjectViewHolder {
    val view = inflater.inflate(R.layout.list_item, parent, false)
    return ViewHolder(view, itemClick)
}

Your onBindViewHolder:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.bindProject(list[position])
}

Then with ViewHolder class create bindProject function.

class ViewHolder(
    view: View,
    private val itemClick: (Project) -> Unit
) : RecyclerView.ViewHolder(view) {

    private val clientTextCount = 7

    val titleTextView: TextView = view.projectTitleTextView
 
    fun bindProject(project: Project) {
        with(project) {
            titleTextView.text = name
            itemView.setOnClickListener { itemClick(this) }
        }
    }
}

Finally in your activity initialize adapter with lazy

private val adapter: ListAdapter by lazy {
    ListAdapter(this, projectList, {
        // Here you can implement your onClick function.
    })
}

For adding new list to RecyclerView initialize below method in your adapter:

fun setProjects(projects: List<Project>) {
    projectList = projects
    notifyDataSetChanged()
}

And call setProjects method anywhere in your activity:

adapter.setProjects(projects)

That's it.

Celinacelinda answered 15/2, 2019 at 8:41 Comment(1)
I have the same approach, but an item click is not triggered until a 2-3 extra clicks on the same line item. Any idea why extra clicks are required?Butyl
C
2

recyclerview with click listener

Add an interface in your adapter class.

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

implement your interface in the mainactivity and overide selectedUser method.

@Override
public void selectedUser(UserModel userModel) {

    startActivity(new Intent(MainActivity.this, SelectedUserActivity.class).putExtra("data",userModel));

}

Full tutorial check out here plus source code. Recyclerview with clicklistener and searchview

Commutate answered 17/12, 2019 at 9:47 Comment(0)
S
1

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, MainActivityCards.class);
        cardViewIntent.putExtra("Position", newPosition);
        c.startActivity(cardViewIntent);
    }
});
  • v is View from onCreateViewHolder
  • c is Context
Saidel answered 18/7, 2015 at 11:15 Comment(0)
E
1

I have looked thorugh all of the anwers and was not quite satasifed. I found much easier and faster solution. Wanted to share for future readers.

  1. Choose any View inside your single recycler item.
  2. Get parent of this View (Make sure you cast to appropirate ViewGroup )
  3. Set your onClickListener to this parent.

Sample code (It is written inside your onBindViewHolder method of your adapter ):

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {

    ConstraintLayout parent = (ConstraintLayout) holder.title.getParent();
    parent.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(context, "Clicked recycler view item at position " + position, Toast.LENGTH_SHORT).show();
        }
    });
}
Emeritaemeritus answered 25/1, 2019 at 12:53 Comment(0)
B
0

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

Barbarism answered 1/7, 2015 at 10:4 Comment(0)
L
0

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;
    }
};
Leveret answered 9/8, 2015 at 20:19 Comment(0)
B
0

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();
    }
}
Billionaire answered 17/8, 2015 at 12:57 Comment(0)
O
0

Usually you have more than one element in your CardView, so that you need an layout view to wrap and organize them.
You can add an OnClickListener to that layout view.
1. Add an id to your layout. In this case a LinearLayout

<android.support.v7.widget.CardView
 .....>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/card_view_linearLayout">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="name"
            android:id="@+id/card_view_name" />

        ...

    </LinearLayout>

</android.support.v7.widget.CardView>

$ 2. Get the layout view in your inner ViewHolder class.

public static class ViewHolder extends RecyclerView.ViewHolder{
    private TextView nameView;
    ...
    private LinearLayout linearLayout;
    public ViewHolder(View itemView) {
        super(itemView);
        nameView = (TextView)itemView.findViewById(R.id.card_view_name);
        ...
        linearLayout = (LinearLayout)itemView.findViewById(R.id.card_view_linearLayout);
    }
}

$ 3. Add the listener to your layout in onBindViewHolder and use a callback to send data to the Activity or Fragment(not tested).

@Override
public void onBindViewHolder(TrackAdapter.ViewHolder holder, final int position) {
    String str = mStringList.get(position);

    holder.nameView.setText(str);
    ...
    holder.linearLayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            callback.itemCallback(mStringList.get(position));
        }
    });
}

how to use callbacks is another story

Omniscient answered 15/5, 2016 at 20:32 Comment(0)
A
0

Step 1 ) Write the click interface

Create an interface named RecyclerViewClickListener.java and add below code. Here we declare two methods onClick and onLongClick to identify item click and long click respectively.

package com.androidtutorialshub.recyclerviewtutorial.Helper;

import android.view.View;

public interface RecyclerViewClickListener {
    void onClick(View view, int position);

    void onLongClick(View view, int position);
}

Step 2 ) Write the Item Touch Class

Create a class named RecyclerViewTouchListener.java and add below code . Here we write the logic to detect click and long press on recycler view item .

package com.androidtutorialshub.recyclerviewtutorial.Helper;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


public class RecyclerViewTouchListener implements RecyclerView.OnItemTouchListener{

    private GestureDetector gestureDetector;
    private RecyclerViewClickListener clickListener;

    public RecyclerViewTouchListener(Context context, final RecyclerView recyclerView, final RecyclerViewClickListener clickListener) {
        this.clickListener = clickListener;
        gestureDetector = 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 && clickListener != null) {
                    clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

        View child = rv.findChildViewUnder(e.getX(), e.getY());
        if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
            clickListener.onClick(child, rv.getChildPosition(child));
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

Step 3 ) Defining click listener

Open MainActivity.java and update the below changes. Here onClick() method will detect click on item and onLongClick will detect long click on item.

recyclerView.addOnItemTouchListener(new RecyclerViewTouchListener(getApplicationContext(), recyclerView, new RecyclerViewClickListener() {
            @Override
            public void onClick(View view, int position) {
                Toast.makeText(getApplicationContext(), bookList.get(position).getTitle() + " is clicked!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongClick(View view, int position) {
                Toast.makeText(getApplicationContext(), bookList.get(position).getTitle() + " is long pressed!", Toast.LENGTH_SHORT).show();

            }
        }));

For more info or Download source code :- http://www.androidtutorialshub.com/android-recyclerview-click-listener-tutorial/

Autotype answered 10/5, 2017 at 10:14 Comment(2)
its click on the on the whole item. if i have one more button in this to perform functionality on this. it's also treat like as itemview click listener?Dictation
You don't need a gesture detector to handle clicks in a RecyclerViewShearwater
T
0

Same answer in Kotlin

inner class MyViewHolder(v: View, myOnClickListener: MyOnClickListener) : RecyclerView.ViewHolder(v) {
    init {
        v.setOnClickListener { v -> myOnClickListener.onClick(v, adapterPosition) }
    }
}

override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): MyViewHolder {
    val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.myview, viewGroup, false)
    return MyViewHolder(view, mOnClickListener)
}

inner class MyOnClickListener {
    fun onClick(view: View, position: Int) {
        val item = mList[position]
        Toast.makeText(view.context, item, Toast.LENGTH_LONG).show()
    }
}
Tonsillectomy answered 25/5, 2017 at 9:33 Comment(0)
R
0

Try this, simple enough. It works for me. BTW, I found that setOnClickListener doesn't take effect for RecyclerView.

recycler.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            // anything todo
        }

        return true;
    }
});
Reasonable answered 14/6, 2017 at 8:35 Comment(0)
B
0

For kotlin handle click on RecyclerView answer based on Jacobs answer

Create class RecyclerItemClickListener:

class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, listner: OnItemClickListener) : RecyclerView.OnItemTouchListener {

    var mGestureDetector: GestureDetector
    var mListner: OnItemClickListener
    
    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)
        fun onLongItemClick(view: View, position: Int)
    }

    init {
        this.mListner = listner
        mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent?): Boolean = true
            
            override fun onLongPress(e: MotionEvent?) {
                val child: View? = recyclerView.findChildViewUnder(e!!.getX(), e.getY())
                if (child != null && mListner != null) {
                    mListner.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
                }
            }
        })
    }

    override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) = Unit

    override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
        val childView: View? = view.findChildViewUnder(e!!.getX(), e.getY())
        if (childView != null && mListner != null && mGestureDetector.onTouchEvent(e)) {
            mListner.onItemClick(childView, view.getChildAdapterPosition(childView))
            return true
        }
        return false
    }

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) = Unit

}

Get click on Any RecyclerView (inside activity/fragment):

recyclerView.addOnItemTouchListener(
    RecyclerItemClickListener(this, recyclerView, object : RecyclerItemClickListener.OnItemClickListener {
        override fun onItemClick(view: View, position: Int) {
            // TODO catch click
        }

        override fun onLongItemClick(view: View, position: Int) {
            // TODO catch click
        }
    })
)
Badalona answered 13/6, 2019 at 12:31 Comment(1)
You don't need a gesture detector to handle clicks in a RecyclerViewShearwater
R
0

Let's see how we can also implement this with Jetpack / AndroidX

You need to create an observable in the viewmodel class like this

private MutableLiveData<Integer> adapterItem = new MutableLiveData<>();

public MutableLiveData<Integer> getAdapterItem() {
    return adapterItem;
}

public void setAdapterItem(int adapterItem) {
    this.getAdapterItem().setValue(adapterItem);
}

Then in the adapter class make sure you pass the viewmodel reference as parameter in the constructor then implement the clicklistener on the viewholder

    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        if(itemView != null){
            itemView.setOnClickListener(v -> {
                int adapterPosition = getAdapterPosition();
                viewModel.setAdapterItem(adapterPosition);
            });

        };
    }

Then from the activity class just observe the changes

    viewModel.getAdapterItem().observe(this, position -> {
        Log.w(TAG, "clicked: " + ridesArray.get(position));
    });
Rarebit answered 7/7, 2019 at 12:27 Comment(1)
Hi Jimmy, the rule was that you should not pass view references to the viewmodel if you don't want memory leaks. In this case we are passing viewmodel to adapter that is managing views. I tried to think of situations under which this would create a memory leak but unfortunately I cannot think of any. VIewmodel lifecycle is larger than adapter and thus I do not think this would create a memory leak. If you have something on your mind, do let me know. I do not claim the absolute truth.Rarebit
I
0

here my way

in activity class:

    public class MyActivity extends AppCompatActivity implements EmployeeAdapter.ClickListener {
    ...
    @Override
    public void onClick(int position) { ... }
    ...
    }

in adapter class:

    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    ...
    @Override
    public void onBindViewHolder(){
         holder.textView1.setOnClickListener(v -> clickListener.onClick(position));
    }
    ...
    public interface ClickListener {
        void onClick(int position);
    }
    ...
    }
Imf answered 13/11, 2019 at 12:12 Comment(1)
You need to set clickListener with a method or constructor.Alf
M
0

Recyclerview adapter with kotlin

You can achive item click listener by two ways in adapter.

1st way is using interface

In your activity class:

class YourActivity : AppCompatActivity(), TestAdapter.ClickListener {
...
override fun itemClicked() {

}
...
}

In your adapter class:

class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
     holder.textView1.setOnClickListener { 
        clickListener.itemClicked(position) 
     }
}
...
interface ClickListener {
     fun itemClicked(position : Int)
}
...
}

2nd way is using callBack invoke

In your adapter class:

class MyAdapter(val callBack: (pos:Int) -> Unit) : RecyclerView.Adapter<MyAdapter.MyViewHolder> {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
     holder.textView1.setOnClickListener { 
        callBack(position)
     }
}
}

In your activity class:

class YourActivity : AppCompatActivity() {
...
val testAdapter = TestAdapter(
            callBack = { index ->
               
            })
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = testAdapter
...
}
Mage answered 12/12, 2022 at 9:26 Comment(0)
R
-1

This works.

public class ServiceListAdapter extends RecyclerView.Adapter<ServiceListAdapter.ViewHolder> {

private final Context mContext;
private List<ServiceListModel> categoryList;
private View.OnClickListener onClickListener;

public ServiceListAdapter(Context mContext, List<ServiceListModel> categoryList, View.OnClickListener onClickListener) {
    this.categoryList = categoryList;
    this.mContext = mContext;
    this.onClickListener = onClickListener;
}

@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    final RowServiceListBinding binding = DataBindingUtil.inflate(inflater, R.layout.row_service_list, parent, false);
    return new ViewHolder(binding.getRoot(), binding);
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    holder.binding.rlService.setOnClickListener(onClickListener);
    holder.binding.rlService.setTag(position);
}

@Override
public int getItemCount() {
    return categoryList.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {
    private final RowServiceListBinding binding;

    public ViewHolder(final View view, final RowServiceListBinding binding) {
        super(view);
        this.binding = binding;
    }

    @UiThread
    public void bind(final ServiceListModel mAddressModel) {
        //this.binding.setAddress(mAddressModel);
    }
}
}

Use in activity/fragment

ServiceListAdapter adapter = new ServiceListAdapter(context, serviceList, new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.rlService:
                    int pos = (int) v.getTag();
                    serviceList.remove(position);
                    break;
            }
        }
    });
Roddy answered 12/2, 2020 at 7:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.