How to implement Android Recyclerview item click AND checkbox item click?

6.7k views Asked by At

I had the following holder that worked, i.e. I was able to check/uncheck the checkbox. (The checkbox is part of the RecyclerView card):

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
  holder.bindData(numbers.get(position));
  //in some cases, it will prevent unwanted situations
  holder.checkbox.setOnCheckedChangeListener(null);

  //if true, your checkbox will be selected, else unselected
  holder.checkbox.setChecked(numbers.get(position).isSelected());

  holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
       @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
         numbers.get(holder.getAdapterPosition()).setSelected(isChecked);
       }
  });
}

I wanted to implement click of the item on RecyclerView. So, I took from this solution - please check: https://stackoverflow.com/a/26196831/4013399

However, now, the click of the entire card item works, but the checkbox can not be checked/unchecked. How to solve this?

Please help. Thanks.

Update

I made changes - however, "HERE-1,2 and 3" lines are never entered.

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Log.e("I AM ", "HERE-0");
holder.bindData(numbers.get(position));

final RelativeLayout rlyItem = holder.rlyItem;
final CheckBox checkbox = holder.checkbox;

rlyItem.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View view) {
        mListener.onItemClicked(holder.getLayoutPosition());
        Log.e("I AM ", "HERE-1");
    }
});

checkbox.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View view) {
        if (((CheckBox) view).isChecked()) {
            checkbox.setChecked(false);
            Log.e("I AM ", "HERE-2");
        } else {
            checkbox.setChecked(true);
            Log.e("I AM ", "HERE-3");
        }
        // Inform to Activity or the Fragment where the RecyclerView reside.
        mListener.onItemCheckBoxChecked(((CheckBox) view).isChecked(), holder.getLayoutPosition());
    }
});
//in some cases, it will prevent unwanted situations
holder.checkbox.setOnCheckedChangeListener(null);

//if true, your checkbox will be selected, else unselected
holder.checkbox.setChecked(numbers.get(position).isSelected());

checkbox.setOnCheckedChangeListener(new   CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        numbers.get(holder.getAdapterPosition()).setSelected(isChecked);
        Log.e("I AM ", "HERE-4");
        //Log.e(Integer.toString(holder.getAdapterPosition()), " IS CHECKED");
    }
});

}

5

There are 5 answers

0
Mavya Soni On

First You add the below property in your checkbox

  android:clickable="false"
        android:focusable="false"
        android:longClickable="false"

Below is my itemclick

 recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position) {
                        Utils.hideSoftKeyboard(getActivity());
                       cityAdapter.itemSelected(position);
                    }
                }));

Add below method in your adapter :

 public void itemSelected(final int position) {
        if (townModelArrayList != null && !townModelArrayList.isEmpty()) {
            townModelArrayList.get(position).setSelected(!townModelArrayList.get(position).isSelected());
            notifyDataSetChanged();
        }
    }
2
Piyush On

Simply call performClick() for your checkbox on click of your adapter inflated view in adapter class.

 holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            holder.checkbox.performClick();
        }
    });
10
ישו אוהב אותך On

TL; DR

To implement RecyclerView item click and a clickable view in RecyclerView item, You need to define listener for each of them.

First, you need to define the layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
  <RelativeLayout
      android:id="@+id/item__rly"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="?android:selectableItemBackground"
      android:clickable="true"
      >

    <CheckBox
    android:id="@+id/item_cbx"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Sample CheckBox" />

  </RelativeLayout>

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

From the above xml code, you can find that the RelativeLayout using:

android:background="?android:selectableItemBackground"
android:clickable="true"

This is to make the item having an animation when clicked.

Second, you need to define click listener interface within your Adapter, something like this:

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

  private List<YourData> mDatas;

  // Define listener member variable
  private static OnRecyclerViewItemClickListener mListener;

  // Define the listener interface
  public interface OnRecyclerViewItemClickListener {
    void onItemClicked(int position);
    void onItemCheckBoxChecked(boolean isChecked, int position);
  }

  // Define the method that allows the parent activity or fragment to define the listener.
  public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener listener) {
    this.mListener = listener;
  }

  public static class ViewHolder extends RecyclerView.ViewHolder {
    RelativeLayout rlyItem;
    CheckBox cbxSample;

    // We also create a constructor that accepts the entire item row
    // and does the view lookups to find each subview
    public ViewHolder(View itemView) {
      // Stores the itemView in a public final member variable that can be used
      // to access the context from any ViewHolder instance.
      super(itemView);
      rlyItem = (RelativeLayout) itemView.findViewById(R.id.item__rly);
      cbxSample = (CheckBox) itemView.findViewById(R.id.item_cbx);
    }
  }

  // Usually involves inflating a layout from XML and returning the holder
  @Override public ViewHolder onCreateViewHolder(ViewGroup parent,
      int viewType) {
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);

    // Inflate the custom layout
    View viewHolder = inflater.inflate(R.layout.item_layout, parent, false);

    // Return a new holder instance
    return new ViewHolder(viewHolder);
  }

  // Involves populating data into the item through holder
  @Override public void onBindViewHolder(final ViewHolder viewHolder, int position) {
    // Get the data model based on position
    final YourData data = mDatas.get(position);

    final RelativeLayout rlyItem = viewHolder.rlyItem;
    CheckBox cbxSample = viewHolder.cbxSample;

    rlyItem.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        mListener.onItemClicked(viewHolder.getLayoutPosition());
      }
    });

    cbxSample.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        if (((CheckBox) v).isChecked()) {
          cbxSample.setChecked(false);
        } else {
          cbxSample.setChecked(true);
        }
        // Inform to Activity or the Fragment where the RecyclerView reside.
        mListener.onItemCheckBoxChecked(((CheckBox) v).isChecked(), viewHolder.getLayoutPosition());
      }
    });

  }

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

Then, in your Activity or Fragment where RecyclerView code reside, you need to set the listener:

yourAdapter.setOnRecyclerViewItemClickListener(new YourAdapter.OnRecyclerViewItemClickListener() {
  @Override 
  public void onItemClicked(int position) {
    // Do something when item clicked.   
  }

  @Override
  public void onItemCheckBoxChecked(boolean isChecked, int position) {
    // Do something when check box check state change.
  }
});

Addition:
To hold the the state of item in your ReyclerView, you need to use SparseBooleanArray

0
Zac On

I solved this problem by removing the whole class referenced in the question link (https://stackoverflow.com/a/26196831/4013399). Instead I implemented an onClick listener only for the checkbox. And for the whole card view item click?, you may ask. For that, I simply implemented another onClick listener for a layout that contained my textbox. Also, to save the state of the checkboxes a simple setting and getting of key,value pairs like (checkbox position, "1") (where 1 indicates checked) and simultaneously updating this in the SharedPreferences worked.

1
Chathura Jayanath On

I wrote a library to handle android recycler view item click event. You can find whole tutorial in https://github.com/ChathuraHettiarachchi/RecycleClick

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });

or to handle item long press you can use

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
                return true;
            }
        });

to handle checkbox click you need to setCheckChangeListner on your adapter