I have ListView with my own layout and CustomCursorAdapter. Every row has it's own checkbox. So... it's absolutely clear that during sroll the checkboxes loose their states. The only stuff I found is Android save Checkbox State in ListView with Cursor Adapter but there is no answer there. And one more question. I had the same problem with my CustorArrayAdapter. I solved that problem using SparseBooleanArray to keep checkboxes states. It works fine, but every scroll calls onCheckedChanged. That's normal? The deal is my list view describes alarm elements and periodic calls (of onCheckedChanged) start/stop the alarms. A lot of unnesseccary actions.
I had the similar issue with my ListView
with CheckBox
and what I did to get rid of the problem:
false
, means no CheckBox is checked yet.public class MyDataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private ArrayList<String> list = new ArrayList<String>();
private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>();
// itemChecked will store the position of the checked items.
public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
for (int i = 0; i < this.getCount(); i++) {
itemChecked.add(i, false); // initializes all items value with false
}
}
public View getView(final int pos, View inView, ViewGroup parent) {
if (inView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inView = inflater.inflate(R.layout.your_layout_file, null);
}
final CheckBox cBox = (CheckBox) inView.findViewById(R.id.bcheck); // your
// CheckBox
cBox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v.findViewById(R.id.your_checkbox_id);
if (cb.isChecked()) {
itemChecked.set(pos, true);
// do some operations here
} else if (!cb.isChecked()) {
itemChecked.set(pos, false);
// do some operations here
}
}
});
cBox.setChecked(itemChecked.get(pos)); // this will Check or Uncheck the
// CheckBox in ListView
// according to their original
// position and CheckBox never
// loss his State when you
// Scroll the List Items.
return inView;
}}
There are a few concerns with the ListView when having checkable items in it. I would suggest the following link:
http://tokudu.com/2010/android-checkable-linear-layout/
I think it's close to what you want.
I was also facing a similar kind of problem, so after lot of reading I solved this problem like this:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listview, null);
holder = new ViewHolder();
holder.nameView = (TextView)convertView.findViewById(R.id.textView1);
holder.numberView = (TextView)convertView.findViewById(R.id.textView2);
holder.cb = (CheckBox)convertView.findViewById(R.id.checkBox1);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.nameView.setText(mData.get(position).toString());
holder.numberView.setText(mNumber.get(position).toString());
holder.cb.setChecked(false);
holder.cb.setTag(position);
if(selected.indexOf(mNumber.get(position).toString()) >= 0)
{
holder.cb.setChecked(true);
}
return convertView;
}
}
Here what I am doing that on getView() I am unchecking all the checkboxes and checking again manually those which I need to be checked according to the textview it corresponds. So if the user scroll down after checking the first checkbox, all the checkbox in the view will get unchecked and if he again scrolls up then also all the checkboxes will be unchecked but then the one he clicked before will be again rechecked.
I decided to try with setViewBinder method. Сheckboxes state is stored in SparseBooleanArray. Сheckbox state changes as you click checkbox itself, and on the entire cell.
My Row: | TextView | CheckBox |
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ..
private SparseBooleanArray checkedItems = new SparseBooleanArray(); //for storing item state
startManagingCursor(cursor);
String[] from = new String[] { dbAdapter.COLUMN_NAME, dbAdapter.COLUMN_CHECK };
int[] to = new int[] { R.id.item_name, R.id.item_check };
recordsAdapter = new SimpleCursorAdapter(this, R.layout.items, cursor, from, to);
recordsAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (columnIndex == 2) { //2 - R.id.item_check
final CheckBox cb = (CheckBox) view;
final int rowID = cursor.getInt(0); //cursor.getInt(0) - _id from table
if (checkedItems.indexOfKey(rowID) >= 0) { //checkedItems contains rowID?
cb.setChecked(checkedItems.get(rowID));
} else if (cursor.getInt(2) > 0) { //cursor.getInt(2): 0 - false, 1 - true
checkedItems.append(rowID, true);
cb.setChecked(true);
} else {
cb.setChecked(false);
}
cb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkedItems.indexOfKey(rowID) >= 0) {
checkedItems.put(rowID, !(checkedItems.get(rowID)));
} else {
checkedItems.append(rowID, true);
}
cb.setChecked(checkedItems.get(rowID));
dbAdapter.updateItem(rowID, checkedItems.get(rowID)?1:0);
}
});
return true;
}
return false;
}
});
itemsList.setAdapter(recordsAdapter);
itemsList.setOnItemClickListener(this);
// ..
}
//if click on TextView of row - CheckBox of row is set/unset
@Override
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
TextView tv = (TextView) view.findViewById(R.id.item_name);
ViewGroup row = (ViewGroup) tv.getParent();
CheckBox cb = (CheckBox) row.getChildAt(1);
cb.performClick();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With