ListView Holder check checbox Bug

喜夏-厌秋 提交于 2019-12-13 04:40:20

问题


I'm developing an app with a custom layout and an arrayAdapter:

The problem is when I check one Box the app automatically check another 2 boxes!

I created a list where I put the positions of checkboxes and show that nothing its wrong! I think the problem is when I do the recycle!

Lets view some code; This is my ArrayAdapter:

class VivzAdapter extends ArrayAdapter<String> implements OnCheckedChangeListener {
Context context;
int[] images;
String[] titlesArray, descrptionArray;
List<Integer> positions = new ArrayList<Integer>();

VivzAdapter(Context context, String[] titles, int[] images, String[] description) {

    super(context, R.layout.single_row, R.id.textView1, titles);
    this.context = context;
    this.images = images;
    this.titlesArray = titles;
    this.descrptionArray = description;
}

class MyViewHolder {
    ImageView myImage;
    TextView myTitle;
    TextView myDescription;
    CheckBox box;

    MyViewHolder(View v) {
        myImage = (ImageView) v.findViewById(R.id.imageView1);
        myTitle = (TextView) v.findViewById(R.id.textView1);
        myDescription = (TextView) v.findViewById(R.id.textView2);
        box = (CheckBox) v.findViewById(R.id.checkBox1);
    }
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    MyViewHolder holder = null;
    if (row == null) {
        // 1.ºtime
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        //row contem RelativeLayout(root) em single_row.xml
        row = inflater.inflate(R.layout.single_row, parent, false);
        holder = new MyViewHolder(row);
        row.setTag(holder);
        //Log.d("VIVZ", "Creating a new Row");
    } else {
        //reciclamos aqui, qeremos usar antigo objecto holder
        holder = (MyViewHolder) row.getTag();
        //Log.d("VIVZ", "Recycling stuff");
    }
    holder.myImage.setImageResource(images[position]);
    holder.myTitle.setText(titlesArray[position]);
    holder.myDescription.setText(descrptionArray[position]);
    holder.box.setTag(position);
    holder.box.setOnCheckedChangeListener(this);
    return row;
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if(isChecked){
        int position = (Integer)buttonView.getTag();
        Toast.makeText(getContext(), ""+position, Toast.LENGTH_SHORT).show();
        positions.add(position);
        Log.d("VIVZ", "+ "+position);
    } else {
        int position = (Integer)buttonView.getTag();
        Toast.makeText(getContext(), ""+position, Toast.LENGTH_SHORT).show();
        Log.d("VIVZ", "- "+position);
        positions.remove(position);
    }
    Log.d("VIVZ", positions.toString());
}
}

回答1:


I was stucked in same problem and found the solution. Create a boolean array having size same as no. of elements in the list and initial value false for each list item. Then in getView set position in Id through setId for checkbox. Now set the value of checkbox from boolean array through setChecked method of checkbox. Add onClickListener for checkbox and in this listener change the value in boolean array not checkbox value directly. I hope this resolve your problem also.

Just replace your adapter class with this code :

class VivzAdapter extends ArrayAdapter<String> implements OnCheckedChangeListener {
Context context;
int[] images;
String[] titlesArray, descrptionArray;
List<Integer> positions = new ArrayList<Integer>();

ArrayList<Boolean> arrChecked;

VivzAdapter(Context context, String[] titles, int[] images, String[] description) {

super(context, R.layout.single_row, R.id.textView1, titles);
this.context = context;
this.images = images;
this.titlesArray = titles;
this.descrptionArray = description;

// initialize arrChecked boolean array and add checkbox value as false initially for each item of listview
arrChecked = new ArrayList<Boolean>();
for (int i = 0; i < titles.size(); i++) {
arrChecked.add(false);
}
}

class MyViewHolder {
ImageView myImage;
TextView myTitle;
TextView myDescription;
CheckBox box;

MyViewHolder(View v) {
    myImage = (ImageView) v.findViewById(R.id.imageView1);
    myTitle = (TextView) v.findViewById(R.id.textView1);
    myDescription = (TextView) v.findViewById(R.id.textView2);
    box = (CheckBox) v.findViewById(R.id.checkBox1);
}
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
MyViewHolder holder = null;
if (row == null) {
    // 1.ºtime
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    //row contem RelativeLayout(root) em single_row.xml
    row = inflater.inflate(R.layout.single_row, parent, false);
    holder = new MyViewHolder(row);
    row.setTag(holder);
    //Log.d("VIVZ", "Creating a new Row");
} else {
    //reciclamos aqui, qeremos usar antigo objecto holder
    holder = (MyViewHolder) row.getTag();
    //Log.d("VIVZ", "Recycling stuff");
}
holder.myImage.setImageResource(images[position]);
holder.myTitle.setText(titlesArray[position]);
holder.myDescription.setText(descrptionArray[position]);

//set position as id
holder.box.setId(position);
//set onClickListener of checkbox rather than onCheckedChangeListener
holder.box.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            int id = v.getId();

            if (arrChecked.get(id)) {
                //if checked, make it unchecked
                arrChecked.set(id, false);
            } else {
                //if unchecked, make it checked
                arrChecked.set(id, true);

            }

        }
    });

    //set the value of each checkbox from arrChecked boolean array
    holder.box.setChecked(arrChecked.get(position));

return row;
}
}



回答2:


At the end of getView method you should check if the current position is in the positions array or not, this should fix the problem

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        MyViewHolder holder = null;
        if (row == null) {
            // 1.ºtime
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            //row contem RelativeLayout(root) em single_row.xml
            row = inflater.inflate(R.layout.single_row, parent, false);
            holder = new MyViewHolder(row);
            row.setTag(holder);
            //Log.d("VIVZ", "Creating a new Row");
        } else {
            //reciclamos aqui, qeremos usar antigo objecto holder
            holder = (MyViewHolder) row.getTag();
            //Log.d("VIVZ", "Recycling stuff");
        }
        holder.myImage.setImageResource(images[position]);
        holder.myTitle.setText(titlesArray[position]);
        holder.myDescription.setText(descrptionArray[position]);
        holder.box.setTag(position);
        holder.box.setOnCheckedChangeListener(this);

    ////// Here you should update the checlbox status by checking if the current index is in the position array or not ////////////
boolean isFound = false;
for(int i =0;i<position.size();i++){
if(positions.get(i) == position){ // this line might need casting
isFound = true;
break;
}
holder.box.setChecked(isFound);
}
    return row;
}



回答3:


Use this sample project for ur problem. link to download complete project https://drive.google.com/file/d/0B6C9Pqrvc_CWZHFDcmxKR01rc3c/edit?usp=sharing



来源:https://stackoverflow.com/questions/23706957/listview-holder-check-checbox-bug

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!