Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When scrolling custom ListView, the checkbox value changes

Tags:


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

like image 343
Stefano C. Avatar asked Jul 05 '12 11:07

Stefano C.


2 Answers

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; } 
like image 123
Uallas Avatar answered Sep 30 '22 17:09

Uallas


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

like image 28
Jimit Patel Avatar answered Sep 30 '22 17:09

Jimit Patel