6

I'm trying to create a custom list which will have checkboxes that allow you to select several items from the list.

The list with the checkboxes is displayed ok but if i check a checkbox and then scroll other items further down the list are also checked.

Its basically the same problem as here

I understand that it has something to do with the way android recycles the view but I cant see how to fix this! Can somebody help me???

Thanks -- Mike

Community
  • 1
  • 1
mixkat
  • 3,883
  • 10
  • 40
  • 58

4 Answers4

5

You need a data structure to keep track of which rows are checked. This could be as simple as a bool[] checked.

In your getView, make sure that you set the checkbox state to the contents of checked[position]. You should also set an OnCheckedChangedListener on your check boxes in getView so that they update your data with checked[position] = isChecked.

Yes, the rows in a ListView are recycled, so make sure to populate all the appropriate data for a row before you leave getView.

Matthew
  • 44,826
  • 10
  • 98
  • 87
  • 1
    Excellent works like a charm! I didnt know that the getView method is actually called everytime you scroll! I thought that the whole list is initialised and then the getView method is never called again! – mixkat Mar 25 '11 at 22:06
  • I thought I fixed this but I was wrong.Its weird because in the setOnCheckedChangeListener I must have it the other way around in order to work i.e. if isChecked then set the appropriate field of the array to false and true otherwise. But then when I have to check which boxes are checked everything is messed up.Note: if I set it properly i.e. set the array field to true when the box is checked then it loses everything if i scroll down and back up again.Any ideas why this is happening? – mixkat Mar 26 '11 at 18:06
  • Are you sure that you're calling `setChecked` even for the recycled views? In other words `if (convertView == null) { /* inflate view */ } /* populate views regardless of recycled/non-recycled outside the if statement */` – Matthew Mar 26 '11 at 22:42
  • Im not sure what you mean.Can you have a look at my other thread? i have my code there: http://stackoverflow.com/questions/5444355/android-listview-with-checkbox-problem – mixkat Mar 27 '11 at 00:56
2

You could try implementing OnClickListener for checkbox instead of OnCheckChangedListener. It worked for me.

iluu
  • 406
  • 3
  • 13
0

Check the code below -

public View getView(int position, View convertView, ViewGroup parent){
            View view = convertView;
            ViewHolder holder = new ViewHolder();

            if(view == null){

                view = inflater.inflate(R.layout.list_callcycle_blue, null);                
                holder.llContainer = (LinearLayout) view.findViewById(R.id.ll_container);
                holder.lblLabel = (TextView) view.findViewById(R.id.txt_desc);
                holder.cb = (CheckBox) view.findViewById(R.id.cb_store);

                view.setTag(holder);
            } else {
                holder = (ViewHolder) view.getTag();
            }

            final Object data = getItem(position);
            holder.lblLabel.setText(data.getDescription());

            holder.cb.setTag(position);
            holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                    int position = (Integer) buttonView.getTag();
                    objects.get(position).setChecked(buttonView.isChecked());
                }
            });
            holder.cb.setChecked(isChecked(position));

            return view;
        }

Always keep in mind, use change holder.cb.setOnCheckedChangeListener() i.e. any listener before it's setting data, in our case it is holder.cb.setChecked()

Reason : When we scroll, listview will recycle the views, so if setchecked is used before listeners then it will pick values on the basis of old listener. And if we set it after listener, then it will take latest values

EDITED PART Below part will show how isChecked() and setChecked() methods used for retrieving checked data

/*
 * This function is in your Custom Adapter Class
 */
private boolean isChecked(int position){
    return object(position).isChecked();
}


/**
 * Getter Setter Class / Data Model Class that defines your object
 */
private class MyObject{
    private boolean isChecked;
    private String a, b, c, orWhateverYourObjectNeeds;

    public void setChecked(boolean isChecked){
        this.isChecked = isChecked;
    }

    public boolean isChecked(){
        return isChecked
    }
}
Jimit Patel
  • 4,265
  • 2
  • 34
  • 58
0

Create an ArrayList<Integer>. add a OnCheckChangedListener to your checkbox. Inside the changed method, add or remove the list view position to the ArrayList<Integer>.

in your getView method, check to see if the ArrayList<Integer> contains the current list view position. if it contains the position, set checked to true, otherwise false.

every time you click a checkbox, either add or remove the Integer from the ArrayList.

james
  • 26,141
  • 19
  • 95
  • 113