Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Kevin Faust
Kevin Faust
15,353 Points

recyclerview and checkboxes

Hi

Due to recyclerview having the viewholder pattern, when a checbox is clicked and when you scroll down, there will be other boxes checked. I was wondering the way to go about this. StackOverflows solution have been too advanced and none of the solutions worked for me.

Thanks

4 Answers

Andrew Sheragy
Andrew Sheragy
16,379 Points

Yes in the onBindViewHolder function put an onClickListener on the holder.checkDisBox. You'll also need to make a final int variable for the position so when the onClick is triggered it has the position available.

final int pos = position;
holder.checkDisBox.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
     ..update your numbers array at position "pos" to be checked or unchecked (opposite of current value)
   }
  });
Kevin Faust
Kevin Faust
15,353 Points

Oh my goodness :O IT FINALLY WORKS!! I was staring at your answer for a while trying to see how that would work and I'm beginning to see what we did. Thank you for the help!

Andrew Sheragy
Andrew Sheragy
16,379 Points

Does your onBindViewHolder always set the checkbox to checked or unchecked? If not it will use its checked state from the previous view that used it.

Kevin Faust
Kevin Faust
15,353 Points

My onBindViewHolder is just assigning text to a textfield. I haven't done anything to my checkboxes. I know that it's using the checked state from the previous view but I'm wondering how I can fix that / what one would usually do.

Ben Deitch
Ben Deitch
Treehouse Teacher

Yep, Andrew's right. You likely need to set either checked or unchecked explicitly each time a View is retrieved. I think you'll just have to keep track of which items are checked, and then use the getAdapterPosition method (or something like it) to get the position and then set checked vs not checked on each View as they get reused.

Kevin Faust
Kevin Faust
15,353 Points

Can you give an example using code of what you said? I dont know how to go about this with words alone. Thanks

Ben Deitch
Ben Deitch
Treehouse Teacher

Does this help? Looks like I initialize the Adapter with a List of Strings, and then use the position parameter in onBindViewHolder to determine the position and set the correct String. I don't think this ever had enough views to see any getting reused though. So I'm hesitant to say it's exactly what you're looking for.

https://github.com/bfdeitch/MaterialNavDrawer/blob/master/app/src/main/java/com/ps/materialnavdrawer/DrawerAdapter.java

Andrew Sheragy
Andrew Sheragy
16,379 Points

Can you paste the code for your RecyclerView.Adapter class?

Kevin Faust
Kevin Faust
15,353 Points
public class myAdapter extends RecyclerView.Adapter<myAdapter.ViewHolder> {

    private List<numbers> mNumbers = Collections.emptyList();

    public myAdapter (List<numbers> numbers) {
        mNumbers = numbers;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v  = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_slot, parent, false);
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }


    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        holder.bindNumbers(mNumbers.get(position));
    }

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


    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        TextView numberText;
        EditText checklistText;
        Button deleteButton;
        CheckBox checkDisBox;

        public ViewHolder(View itemView) {
            super(itemView);
            numberText = (TextView) itemView.findViewById(R.id.number);
            checklistText = (EditText) itemView.findViewById(R.id.editText);
            deleteButton = (Button) itemView.findViewById(R.id.deleteButton);
            checkDisBox = (CheckBox) itemView.findViewById(R.id.checkBox);

            deleteButton.setOnClickListener(this);
        }

        public void bindNumbers(numbers numbers) {
            numberText.setText(numbers.getInt() + "");
        }

        @Override
        public void onClick(View v) {
            mNumbers.remove(getAdapterPosition());
            notifyItemRemoved(getAdapterPosition());
        }
    }
}
Andrew Sheragy
Andrew Sheragy
16,379 Points

For checking boxes you need an onClickListener to save the state of the checkbox, ignore that for right now there are still a few other things you can do to make some progress

  • Add a boolean field to your numbers object to indicate if a box is checked, add getChecked() to return that field
  • Temporarily initialize a few of these to "true" for testing purposes
  • on bindNumbers add checkDisBox.setChecked(numbers.getChecked())

Then you can test the scrolling on your list and only the checkboxes in the positions you set as "true" should stay checked as they go on and off the screen.

The last step is to add an onClickListener to the checkbox so your numbers object in that position get updated to "true" when a box is checked and "false" when unchecked.

Kevin Faust
Kevin Faust
15,353 Points

I added a boolean field to my numbers object and initialized it as false. I created a getter and setter method for the boolean field. I added setChecked(numbers.getChecked()) in my bindNumbers method.

I didn't understand what to do after. I added an onclick listener to my checkbox but am unsure where exactly im supposed to put it. In the bindNumbers() method? Also im not sure what to put inside the onclick listener