Reputation: 3785
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
Upvotes: 6
Views: 4706
Reputation: 4297
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
}
}
Upvotes: 0
Reputation: 406
You could try implementing OnClickListener for checkbox instead of OnCheckChangedListener. It worked for me.
Upvotes: 2
Reputation: 26271
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
.
Upvotes: 0
Reputation: 44919
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
.
Upvotes: 5