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.
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 had the similar issue with my ListView
with CheckBox
and what I did to get rid of the problem:
- Create an ArrayList of Boolean Object to store the state of the each CheckBox
- Initializes the ArrayList items to default value
false
, means no CheckBox is checked yet. - When you click on CheckBox. Set a check against Checked/Unchecked state and store that value in ArrayList.
- Now set that position to CheckBox using setChecked() method.
See this code snippet:
public class DataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private ArrayList<String> list = new ArrayList<String>();
private ArrayList<Boolean> checkedItems = new ArrayList<Boolean>();
public DataAdapter(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++) {
checkedItems.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.list_item, null);
}
final CheckBox checkBox = (CheckBox) inView.findViewById(R.id.bcheck);
checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox cb = (CheckBox) v;
if (cb.isChecked()) {
checkedItems.set(pos, true);
} else if (!cb.isChecked()) {
checkedItems.set(pos, false);
}
}
});
checkBox.setChecked(checkedItems.get(pos));
return inView;
}}
cb
instead of using cbox
directly? –
Jeanene 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();
}
I can't understand, why it is not possible (like in HTML) to define a ViewElement as an array in XML. I.e.:
<CheckBox
android:id="@+id/myCheckBox[]"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
and store a value int it [true|false]. This would make life much easier, instead of using complicated source-frickle. Also the data (i.e. when switching from landscape to portrait) should be kept by android and not getting lost.
Perhaps in API 117, version toothscratch...
(sry, cannot comment yet) - regarding Answer of Vikas Patidar, which works for me - be aware when using async loading (like using a Loader) because getCount in the Constructor of the Adapter will be zero.
You end up with indexing errors (cause the ArrayList never gets populated). Use SparseBooleanArray instead of ArrayList and it will work with async loading as well.
Might be late here, to add up on Vikas Patidar's answer here is a complete implementation using the bindView
method for those of you who are suing a CursorAdapter:
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder holder = (ViewHolder) view.getTag();
final int position = cursor.getPosition();
String name = (cursor.getString(cursor.getColumnIndexOrThrow("NotificationDateFor")));
String image = cursor.getString(cursor.getColumnIndexOrThrow("imageUri"));
System.out.println("cursor.getPosition(test): "+cursor.getPosition());
holder.nametext.setText(name);
// setImage(image, holder.iv);
holder.chk.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
if (holder.chk.isChecked()) {
itemChecked.set(position, true);
System.out.println("cursor.getPosition(true): "+position);
} else if (!holder.chk.isChecked()) {
itemChecked.set(position, false);
System.out.println("cursor.getPosition(false): "+position);
// AddDelete
}
}
});
holder.chk.setChecked(itemChecked.get(cursor.getPosition()));
}
Note: final int position = cursor.getPosition();
is significant!
You can save yourself alot of hassle by utilizing Listview's built-in multiple selection mode.
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
© 2022 - 2024 — McMap. All rights reserved.