4

I am working with RecyclerView and CardView. I want to attach OnClickListner to each card. I tried with many answers available on stackoverflow, but they are not working for me. So far I have tried -

public class SubjectAdapter extends RecyclerView.Adapter<SubjectAdapter.ViewHolder> implements View.OnClickListener,
    View.OnLongClickListener{

private static final String LOGCAT = "SubjectAdapter";
private final Context mContext;

List<Subject> SubjectsList;

public SubjectAdapter(Context context) {
    super();
    this.mContext = context;
    SQLiteDatabase.loadLibs(mContext);
    DBHelper myDbHelper = new DBHelper(mContext);
    SubjectsList = new ArrayList<Subject>();
    SubjectsList = myDbHelper.getAllSubjects();
    myDbHelper.close();
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View v = LayoutInflater.from(viewGroup.getContext())
            .inflate(R.layout.subject_cardview_row, viewGroup, false);
    ViewHolder viewHolder = new ViewHolder(v);

    // Below two lines are NOT working
    viewHolder.tvSubjectName.setOnClickListener(this);
    //viewHolder.setOnClickListener(this);

    return viewHolder;
}

@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
    Subject subject = SubjectsList.get(i);
    viewHolder.tvSubjectName.setText(subject.getSubject_Name());
    viewHolder.tvCounts.setText(String.valueOf(subject.getSubject_Number_of_Questions()));

    // Below two lines are NOT working
    viewHolder.tvSubjectName.setOnClickListener(this);
    //viewHolder.setOnClickListener(this);
}

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

@Override
public void onClick(View v) {
    // It's not working either
    ViewHolder holder = (ViewHolder) v.getTag();
    int position = holder.getPosition();

    if (v.getId() == holder.tvSubjectName.getId()){
        Log.d(LOGCAT, "tvSubjectName onClick at" + position);
        //Toast.makeText(mContext, "tvSubjectName onClick at" + position, Toast.LENGTH_LONG).show();
    } else {
        Log.d(LOGCAT, "RecyclerView Item onClick at " + position);
        //Toast.makeText(mContext, "RecyclerView Item onClick at " + position, Toast.LENGTH_LONG).show();
    }
}

@Override
public boolean onLongClick(View v) {
    return false;
}

class ViewHolder extends RecyclerView.ViewHolder {

    public TextView tvSubjectName;
    public TextView tvCounts;

    public ViewHolder(View itemView) {
        super(itemView);
        tvSubjectName = (TextView) itemView.findViewById(R.id.tv_subject_name);
        tvCounts = (TextView) itemView.findViewById(R.id.tv_text_counts);
    }
}
}

As one can see, I have tried setOnClickListener with both onCreateViewHolder and onBindViewHolder, also as separate onClick, but none of them seems to be working for me. So, I want to know, How to add OnClickListner to CardView?

Dr. Atul Tiwari
  • 1,085
  • 5
  • 22
  • 46

5 Answers5

9

View returned by onClick does not necessarily correspond to View row hierarchy of the recycler view. I think you should modify onBindViewHolder with

@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
   final Subject subject = SubjectsList.get(i); 
   viewHolder.tvSubjectName.setOnClickListener(new View.OnClickListener(){


    @Override
    public void onClick(View v) {
        Log.d(LOGCAT, "tvSubjectName onClick at" + i);
       // etc
    }

   });
...
}

If you use long click then replace View.OnClickListener with View.OnLongClickListener and onClick with onLongClick.

inmyth
  • 8,880
  • 4
  • 47
  • 52
  • hi, it does work for `OnClickListener` but showing error for `OnLongClickListener`. Also I think you meant `View.OnClickListener`, in your code sample. I will mark best answer, as soon as I get it to work for `OnLongClickListener` too. thanks. upvote from me. – Dr. Atul Tiwari May 09 '15 at 17:27
  • 2. also, is there anyway by which something like this can be achieved - `viewHolder.setOnClickListener` ? – Dr. Atul Tiwari May 09 '15 at 17:35
  • I got it now, you mixed `onClickLinstner` (which requires `setOnClickListener`) and `onLongClickListner`.(which requires `setOnLongClickListener`). Your suggestion works after these correction. Kindly correct them. But I couldn't find a way to directly get `viewHolder.setOnClickListener`, other than using `onClickListner` to whole layout. Thanks. – Dr. Atul Tiwari May 09 '15 at 18:01
  • Wah, you edited at the same time, while I was mentioning the same in comments. :P – Dr. Atul Tiwari May 09 '15 at 18:02
  • 1
    Well thank you. To answer your#2 yes you can. If you have the id of the root of your row `R.layout.subject_cardview_row` which I assume is CardView, then you can obtain the reference in `ViewHolder` the same way you did `TextView tvSubjectName, tvCounts`. Then you can attach a click listener to it. – inmyth May 09 '15 at 18:17
4

This worked for me ! Put the setOnClickListener-method inside the constructor of your ViewHolder class.

class ViewHolder extends RecyclerView.ViewHolder
{
    public TextView tvSubjectName;
    public TextView tvCounts;

    public ViewHolder(View itemView) 
    {
        super(itemView);
        tvSubjectName = (TextView) itemView.findViewById(R.id.tv_subject_name);
        tvCounts = (TextView) itemView.findViewById(R.id.tv_text_counts);

        itemView.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                 //write here the code for wathever you want to do with a card
                 //...
            }
        });

}

}

Nike Sprite
  • 476
  • 2
  • 16
  • it works, but I was getting error whenever i was trying to get position `ViewHolder holder = (ViewHolder) v.getTag(); int position = holder.getPosition();` also even if somehow I could get position, I wouldn't get extra info, which I am able to get from @inmyth's answer (int i, in his answer). Upvote from me. – Dr. Atul Tiwari May 09 '15 at 17:22
  • ok, I got it. I will try with integer, but even then, I would Not be able to get extra info, like `subject.getSubject_Name()` which is in `onBindViewHolder` or is there any way around? – Dr. Atul Tiwari May 09 '15 at 17:47
  • Try to use v.findViewById() inside the onClick and use the TextView get the extra info you want. I think there are better ways to get the extra information, but this is one you can try. – Nike Sprite May 09 '15 at 17:53
  • Hey, thanks for your continuous support, but I have got everything that I needed, from modifying @inmyth's answer (I am commenting him the err in his answer). Wish I could double vote you for your help :) – Dr. Atul Tiwari May 09 '15 at 17:58
  • The method @inmyth uses is the same as I do, the code is only situated on a different place. – Nike Sprite May 09 '15 at 20:04
1

Check out Lucas Rocha's new TwoWayView API.

TwoWayLayoutManager is a simple API on top of LayoutManager that does all the laborious work for you so that you can focus on how the child views are measured, placed, and detached from the RecyclerView.

Follow his site and implementation of the API is relatively simple and might help you through some of the difficult complexities RecyclerView and CardView pose.

http://lucasr.org/2014/07/31/the-new-twowayview/

AlleyOOP
  • 1,536
  • 4
  • 20
  • 43
0

Set OnClickListener to itemView in RecyclerView.ViewHolder constructor, also you can fetch position of cardView using getAdapterPosition() method which can help you to pass the data to new activity using putExtra method of intent. doc for getAdapterPosition method

`

class ViewHolder extends RecyclerView.ViewHolder
{
    public TextView tvSubjectName;
    public TextView tvCounts;

    public ViewHolder(View itemView) 
    {
        super(itemView);
        tvSubjectName = (TextView) itemView.findViewById(R.id.tv_subject_name);
        tvCounts = (TextView) itemView.findViewById(R.id.tv_text_counts);

        itemView.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                 int position = getAdapterPosition();
                 // use position to put extra data
            }
        });
}

`

Nagesh Dhope
  • 797
  • 5
  • 13
0

If you really want to implement onclick listener then do the following

  1. add a View object in your ViewHolderClass and initialize it to the itemView recieved in the constructor

2.setOnClickListener to the view object you declared(in ViewHolder) onBindViewHolder in the Adapter class

this will work for the entire cardView