how to bind a checkbox to a listview

后端 未结 2 909
灰色年华
灰色年华 2021-01-22 09:55

I have a listview containing on each row a textview with a checkbox, so when the checkbox is checked and we scroll down through the listview the checkbox instance will be taken

相关标签:
2条回答
  • 2021-01-22 10:27

    In any Listview, the view are reused. As you scroll through the list, those that scroll up and off screen are recycled and used with newer information as it comes in below.

    You need to keep track of your checkboxes with a sparse array. Mark the index in the array as cherked/unchecked as the user touches each. You then set the state of the checkbox based on the value in the array.

    Here is some example code from an an older app, that does both a "select all" checkboxes as well as manages the entire list of those checked and unchecked. It was for a classroom attendance app I wrote, so it was much easier for a teacher to select "ALL" being in class and then unselect those that weren't present.

    I have two checkboxes in this listview, and two sparse arrays, itemCheckedHere and itemCheckedLate (whether a student is in class, or was late).

    public class MyDataAdapter extends SimpleCursorAdapter {
        private Cursor c;
        private Context context;
        private Long classnum;
        private gradeBookDbAdapter mDbHelper;
    
        public static final int LATE=2;
        public static final int ATTEND=1;
        int idxCol;
        int idx;
    
        // itemChecked will store the position of the checked items.
    
        public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
                int[] to, Long mRowId) {
            super(context, layout, c, from, to);
            this.c = c;
            this.context = context;
            mDbHelper = new gradeBookDbAdapter(context);
            mDbHelper.open();
            classnum = mRowId;
            c.moveToFirst();
    
    
    
        }
        public class ViewHolder{
            public TextView text;
            public TextView text2;
            public ImageView image;
            public CheckBox here;
            public CheckBox late;
        }
    
    
        public View getView(final int pos, View inView, ViewGroup parent) {
            Bitmap bm;
            ImageView studentPhoto;
            View vi=inView;
            final ViewHolder holder;
    
            if (inView == null) {
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                vi = inflater.inflate(R.layout.show_attendance, null);
    
                holder=new ViewHolder();
                holder.text=(TextView)vi.findViewById(R.id.stuname);
                holder.text2=(TextView)vi.findViewById(R.id.stuIndex);
                holder.image=(ImageView)vi.findViewById(R.id.icon);
                holder.here=(CheckBox)vi.findViewById(R.id.attend);
                holder.late=(CheckBox)vi.findViewById(R.id.late);
                vi.setTag(holder);
    
            }
            else
               holder=(ViewHolder)vi.getTag();
    
    
            c.moveToPosition(pos);
            int index = c.getColumnIndex(gradeBookDbAdapter.KEY_NAME);
            String name = c.getString(index);
            holder.text.setText(name);
            index = c.getColumnIndex(gradeBookDbAdapter.KEY_ROWID); 
            String Index = c.getString(index);
            holder.text2.setText(Index);
    
            bm = gradeBookDbAdapter.getStudentPhoto(name);
            if (bm != null) {
                holder.image.setImageBitmap(bm);  
            }           
            else {
                // use icon image
                holder.image.setImageResource(R.drawable.person_icon);
            }
    
    
            // pull out existing attend/late fields and set accordingly
            int attend = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_ATTEND));
            if(attend==1){
               holder.here.setChecked(true);
               itemCheckedHere.set(pos, true);
            }
            //else {
            //   holder.here.setChecked(false);
            //   itemCheckedHere.set(pos, false);
            //}
    
            int late = c.getInt(c.getColumnIndex(gradeBookDbAdapter.KEY_LATE));
            if (late==1){
               holder.late.setChecked(true);
               itemCheckedLate.set(pos, true);
            }
            //else {
            //  holder.late.setChecked(false);
            //    itemCheckedLate.set(pos, false);
            //}
    
    
            if (selectAllTouched) {
                if(selectAll){
                    holder.here.setChecked(true);
                    itemCheckedHere.set(pos, true);
                    int who= new Integer(holder.text2.getText().toString());
                    mDbHelper.updateAttend(who, classnum, ATTEND, 1, attendDate );
                }
                else{
                    holder.here.setChecked(false);
                    itemCheckedHere.set(pos, false);
                    int who = new Integer(holder.text2.getText().toString());
                    mDbHelper.updateAttend(who, classnum, ATTEND, 0, attendDate );
                }
            }
    
    
            holder.here.setOnClickListener(new OnClickListener() {
    
                public void onClick(View v) {
    
                    CheckBox cb = (CheckBox) v.findViewById(R.id.attend);
    
                    if (cb.isChecked()) {
                        itemCheckedHere.set(pos, true); 
                        int Index = new Integer(holder.text2.getText().toString());
                        mDbHelper.updateAttend(Index, classnum, ATTEND, 1, attendDate ); 
                    } else if (!cb.isChecked()) {
                        itemCheckedHere.set(pos, false);
                        int Index = new Integer(holder.text2.getText().toString());
                        mDbHelper.updateAttend(Index, classnum, ATTEND, 0, attendDate );
                    }
                }
            });
            holder.late.setOnClickListener(new OnClickListener() {
    
               public void onClick(View v) {
                    CheckBox cb = (CheckBox) v.findViewById(R.id.late);
    
                    if (cb.isChecked()) {
                       itemCheckedLate.set(pos, true);
                       int Index = new Integer(holder.text2.getText().toString());
                       mDbHelper.updateAttend(Index, classnum, LATE, 1, attendDate );
                    } else if (!cb.isChecked()) {
                       itemCheckedLate.set(pos, false);
                       int Index = new Integer(holder.text2.getText().toString());
                       mDbHelper.updateAttend(Index, classnum, LATE, 0, attendDate );
                    }
                }
            });
    
    
            holder.here.setChecked(itemCheckedHere.get(pos)); // this will Check or Uncheck the
            holder.late.setChecked(itemCheckedLate.get(pos)); // this will Check or Uncheck the
            // CheckBox in ListView
            // according to their original
            // position and CheckBox never
            // loss his State when you
            // Scroll the List Items.
    
            return vi;
        }
    
    }
    

    }

    0 讨论(0)
  • 2021-01-22 10:28

    It looks like your OnCheckedChangedListener is the problem here. If you look at your code, see that every checkbox is getting a reference to the same listener. So when you check one box, you're setting every other box as checked too - and you're not updating your backing data, either.

    Your OnCheckedChangedListener should not be updating the view state of the checkbox - the callback is fired because the state has already changed.

    So you need to do the following steps when a user checks the checkbox:

    1. Figure out which item was checked, and how that corresponds to your data
    2. Update your data to suit the new checked/unchecked state
    3. Notify your adapter of a data change/update your cursor

    You could do this something like the following, tagging the view with the ID of the row it represents:

    public boolean setViewValue(View view, Cursor cursor, int columnIndex){
        if(view.getId() == R.id.bt_rating){
            view.setTag(cursor.getInt(cursor.getColumnIndex(SomeDBContract.ID)));
            ((CheckBox)view).setChecked(Boolean.valueOf(cursor.getString(cursor.getColumnIndex("Favorites"))));
            ((CheckBox)view).setOnCheckedChangeListener(myCheckChangList);
            return true; //true because the data was bound to the view
        }
        return false;
    }
    

    Then, in your listener you can update your database according to that ID:

    CheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                 int rowId = (int) buttonView.getTag();
                 // Handle updating the database as per normal
                 updateSomeDbRowAsChecked(rowId, isChecked);
            }
        };
    

    Finally, you'll need to update your cursor adapter with a new cursor once the database row is updated:

     myAdapter.swapCursor(newCursor);
    

    You'll have to adjust all of this to suit your code, but it should give you an idea of one way you can approach this problem.

    0 讨论(0)
提交回复
热议问题