When scrolling custom ListView, the checkbox value changes

14,875

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).

Share:
14,875

Related videos on Youtube

Stefano C.
Author by

Stefano C.

Updated on September 14, 2022

Comments

  • Stefano C.
    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.
    Stefano C. almost 12 years
    I try your solution but when i click on checkBoxs and then scroll the chekboxs become all uncheched....why???
  • Bhargav Panchal
    Bhargav Panchal almost 12 years
    that logic work for me. check value of checkedItem or post your changed code this logic is applied.
  • Stefano C.
    Stefano C. almost 12 years
    Hi, i change my code as your answer. I used the same code but checkbox lost their value :(..
  • Bhargav Panchal
    Bhargav Panchal almost 12 years
    If this is not work for tell me your email id i will send you demo application.
  • Stefano C.
    Stefano C. almost 12 years
    thanks...my email is [email protected] ...i'm waiting for your application :)
  • Kalel Wade
    Kalel Wade over 8 years
    Helped mainly for how you explained the Reason for putting the set value after set listener.