When scrolling custom ListView, the checkbox value changes
Solution 1
I solved my problem just changing the "setOnCheckedChangeListener" to "setOnClickListener"
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
CheckBox cbItemChecklist = new CheckBox(context);
holder = new ViewHolder();
holder.cbItemChecklist = cbItemChecklist;
convertView = cbItemChecklist;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final ItemChecklist itemChecklist = itensChecklist.get(position);
holder.cbItemChecklist.setText(itemChecklist
.getDescricaoItemChecklist());
holder.cbItemChecklist.setChecked(itemChecklist.isChecked());
holder.cbItemChecklist
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(itemChecklist.isChecked()){
itemChecklist.setChecked(false);
} else {
itemChecklist.setChecked(true);
}
}
});
return convertView;
}
Solution 2
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
Solution 3
You didn't cover the case convertView != null, this is what happens when scrolling up and down. You should implement a way to recycle the convertView (better) or just ignore it and give a fresh View back in this case too (worse).
Related videos on Youtube
Stefano C.
Updated on September 14, 2022Comments
-
Stefano C. over 1 year
What I have: a custom listview with Textviews and checkbox.
Problem: Suppose my screen can show only 6 items of list at time, and the others are invisible. So I checked the first element on the list (item at position 0). I scroll down to see all my list, when I scroll up at first element (item at position 0) the checkbox is checked correctly. Great! But now there are new items thath are checked too, for example the item at position 8 (because when I scroll the list (for theRycicling) it become the new item at position 0..remember my screen shows only 7 elements at time). And it become checked, but i have never checked it!
Question: How i can avoid this problem? I don't want that the checkbox that I don't click change their status.
Below my adapter for listView with the getView function where I have implemented the setOnCheckedChangeListener:public class NewQAAdapterSelectFriends extends BaseAdapter { private LayoutInflater mInflater; private Person[] data; public NewQAAdapterSelectFriends(Context context) { mInflater = LayoutInflater.from(context); } public void setData(Person[] data) { this.data = data; } @Override public int getCount() { return data.length; } @Override public Object getItem(int item) { return data[item]; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.item_select_friends, null); final ViewHolder viewHolder = new ViewHolder(); viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName); viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname); viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage); viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox); convertView.setTag(viewHolder); viewHolder.nameText.setTag(viewHolder.nameText); viewHolder.nameText.setTag(viewHolder.surnameText); viewHolder.contactImage.setTag(data[position]); viewHolder.checkBox.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) { Person element = (Person) viewHolder.checkBox.getTag(); if(isChecked){ element.setCheck(buttonView.isChecked()); //data[position].setCheck(true); //this is equivalent to previous line } else{ //to-do } } }); viewHolder.checkBox.setTag(data[position]); } else { } ViewHolder holder = (ViewHolder) convertView.getTag(); holder.nameText.setText(data[position].getName()); holder.surnameText.setText(data[position].getSurname()); holder.contactImage.setImageResource(data[position].getPhotoRes()); holder.contactImage.setScaleType(ScaleType.FIT_XY); holder.checkBox.setChecked(data[position].isCheck()); return convertView; } static class ViewHolder { TextView nameText; TextView surnameText; ImageView contactImage; CheckBox checkBox; } }
Thanks for the answers :)
EDIT: With the suggestion i changed my getView like below:
@Override public View getView(final int position, View convertView, ViewGroup parent) { final ViewHolder viewHolder; if (convertView == null) { convertView = mInflater.inflate(R.layout.item_select_friends, null); viewHolder=new ViewHolder(); viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName); viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname); viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage); viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox); convertView.setTag(viewHolder); viewHolder.nameText.setTag(viewHolder.nameText); viewHolder.nameText.setTag(viewHolder.surnameText); viewHolder.contactImage.setTag(data[position]); viewHolder.checkBox.setChecked(data[position].isCheck()); viewHolder.checkBox.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { if(viewHolder.checkBox.isChecked()==true) data[position].setCheck(true); else data[position].setCheck(false); } }); } else{ viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.nameText.setText(data[position].getName()); viewHolder.surnameText.setText(data[position].getSurname()); viewHolder.contactImage.setImageResource(data[position].getPhotoRes()); viewHolder.contactImage.setScaleType(ScaleType.FIT_XY); viewHolder.checkBox.setChecked(data[position].isCheck()); return convertView; }
SITUATION AFTER EDIT: Now, if i check the initial items that are shows on the screen and then I scrool the list, their value is correctly saved. But When I scroll the list and for example i want to check the last tree checkboxs of my list then after I scroll they become uncheked....BUT WHY??????
SOLVED: I solved my problem of getView with this code:
public class NewQAAdapterSelectFriends extends BaseAdapter { private LayoutInflater mInflater; private Person[] data; boolean[] checkBoxState; ViewHolder viewHolder; public NewQAAdapterSelectFriends(Context context) { mInflater = LayoutInflater.from(context); } public void setData(Person[] data) { this.data = data; checkBoxState=new boolean[data.length]; } @Override public int getCount() { return data.length; } @Override public Object getItem(int item) { return data[item]; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.item_select_friends, null); viewHolder=new ViewHolder(); viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName); viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname); viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage); viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox); convertView.setTag(viewHolder); } else{ viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.nameText.setText(data[position].getName()); viewHolder.surnameText.setText(data[position].getSurname()); viewHolder.contactImage.setImageResource(data[position].getPhotoRes()); viewHolder.contactImage.setScaleType(ScaleType.FIT_XY); viewHolder.checkBox.setChecked(checkBoxState[position]); viewHolder.checkBox.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if(((CheckBox)v).isChecked()){ checkBoxState[position]=true; data[position].setCheck(true); }else{ checkBoxState[position]=false; data[position].setCheck(false); } } }); return convertView; } static class ViewHolder { TextView nameText; TextView surnameText; ImageView contactImage; CheckBox checkBox; }
}
I have seen this tutorial to do my getView: http://androidcocktail.blogspot.it/2012/04/adding-checkboxes-to-custom-listview-in.html
-
Stefano C. almost 12 yearsI try your solution but when i click on checkBoxs and then scroll the chekboxs become all uncheched....why???
-
Bhargav Panchal almost 12 yearsthat logic work for me. check value of checkedItem or post your changed code this logic is applied.
-
Stefano C. almost 12 yearsHi, i change my code as your answer. I used the same code but checkbox lost their value :(..
-
Bhargav Panchal almost 12 yearsIf this is not work for tell me your email id i will send you demo application.
-
Stefano C. almost 12 yearsthanks...my email is [email protected] ...i'm waiting for your application :)
-
Kalel Wade over 8 yearsHelped mainly for how you explained the Reason for putting the set value after set listener.