I am building a list and the list contain for every contact a
checkbox to chose which one to modify for example, the problem is that
when the list became longer than the phone screen and the scrolling is
active; when i select a check box , a second one is automatically
selected in the bottom of the list.
the problem is the automatic selection of the second checkbox;
please let me know how can i fix it ??
below is the code i am using for getView method
public View getView(int position, View converView, ViewGroup parent){
View row = converView;
if(row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.edit, parent, false);
}
TextView label = (TextView)row.findViewById(R.id.label);
label.setText(items[position]);
CheckBox cb = (CheckBox)row.findViewById(R.id.del);
ImageView icon = (ImageView)row.findViewById(R.id.icon);
icon.setImageResource(images.get(position));
Log.i("Pos", ""+position);
return row;
}
}
The problem is that list reuses your view (hence the convertView argument in getView).
In your code, if you get a convertView that isn't null, you have to change its checkbox checked state to what is relevant for the new content.
Let's say view1 is first associated with id 1 and you check it.
Then, you scroll and view1 is converted to display id 10. But since the view isn't recreated, it will still have the checkbox state from the item with id 1.
So basically the solution is to store somewhere which items are selected and in our getView method, you would do
cb.setChecked(isItemChecked(position));
And you have to implement isItemChecked(int position);
An inefficient but working implementation would be to use an array of boolean in your activity, let's say
boolean[] itemChecked;
And then in getView, you set a listener on checkbox checked (have to make position final for this to work). You also set the checked state using the array.
cb.setOnCheckedChangeListener (new OnCheckedChangeListener () {
public void onCheckedChanged (CompoundButton btn, boolean isChecked) {
itemChecked[position] = isChecked;
}
});
cb.setChecked(itemChecked[position]);
But again, using an array for that is maybe not the most efficient implementation, especially if you have a huge number of elements in your list.
Yyou can also use a SparseBooleanArray which allows you to use the list position as the key
Works fine for me
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final ViewHolder holder;
final Season season = (Season) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.season, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.season_title);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.season_check_box);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText(season.getTitle());
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
season.setChecked(isChecked);
adapter.notifyDataSetChanged();
}
});
holder.checkBox.setChecked(season.isChecked()); // position is important! Must be before return statement!
return convertView;
}
protected class ViewHolder {
protected TextView title;
protected CheckBox checkBox;
}
This is the best solution for me.
Checkbox auto call onCheckedChange when listview scroll?