1

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

}

Community
  • 1
  • 1
Zac
  • 695
  • 1
  • 11
  • 34

5 Answers5

3

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();
        }
    });
Piyush
  • 18,895
  • 5
  • 32
  • 63
  • Yes I tried this, but made no change. The checkbox is still not clickable. – Zac Dec 20 '16 at 20:31
  • I removed the whole "card item" click and made a textview onClick and checkbox onClick implementation like you did. However, can you now explain how to save the state of the checkbox when the user returns to the activity? That will be helpful. Thanks. – Zac Dec 21 '16 at 00:09
2

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();
        }
    }
Mavya Soni
  • 932
  • 7
  • 15
1

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

0

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.

Community
  • 1
  • 1
Zac
  • 695
  • 1
  • 11
  • 34
-1

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

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
  • I have fixed the above by using your itemclick code... However, my adapter does not recognize the method OnRecyclerViewItemClickListener if I do that in your code - [adapter.setOnRecyclerViewItemClickListener(new adapter.OnRecyclerViewItemClickListener() {...] - How to fix this? – Zac Dec 20 '16 at 08:44
  • Cannot resolve symbol OnRecyclerViewItemClickListener on [new adapter.OnRecyclerViewItemClickListener] – Zac Dec 20 '16 at 08:52
  • Also, because of the RelativeLayout, my Checkbox is not not visible on the card. Please help me understand. – Zac Dec 20 '16 at 09:03
  • Did u check my answer? – Piyush Dec 20 '16 at 09:21
  • @Zac: you need to change `new adapter.OnRecyclerViewItemClickListener()` to `new AdapterClassName.OnRecyclerViewItemClickListener()`. Note that you need to use Adapter class name, not the variable. – ישו אוהב אותך Dec 20 '16 at 09:59
  • Is the checkbox visible when you remove `android:background="?android:selectableItemBackground" android:clickable="true"` from the RelativeLayout? Please try to use LinearLayout instead. – ישו אוהב אותך Dec 20 '16 at 10:05
  • Fixed the adapter error, and made it visible - code is identical to your example. However, still the checkbox can't be clicked! It just behaves like the card was clicked and takes me to another activity-onItemClicked and onItemCheckBoxChecked are never entered [] – Zac Dec 20 '16 at 20:18
  • Please see my updated code. Doesn't work - I see a slight animation when the checkbox is clicked, but then the Card item click method happens and it does not get checked. Very strange. – Zac Dec 20 '16 at 21:19
  • One last thing: Can you please explain this line - [mListener.onItemCheckBoxChecked(((CheckBox) view).isChecked(), holder.getLayoutPosition());] - how does this work? - Also, any tutorial on using SparseBooleanArray to save states would be appreciated. – Zac Dec 20 '16 at 23:58
  • That's very strange. I slightly change the example from my working project. `mListener.onItemCheckBoxChecked(((CheckBox) view).isChecked(), holder.getLayoutPosition())` means call the listener which implement the onItemCheckBoxChecked with checkbox state value and from the data in the selected position. – ישו אוהב אותך Dec 21 '16 at 00:24