как привязать чекбокс к списку

У меня есть список, содержащий в каждой строке текстовое представление с флажком, поэтому, когда флажок установлен, и мы прокручиваем список вниз, экземпляр флажка будет перенесен из одного места в другое (повторно использован ..), и у меня есть несколько отмеченных флажков, как чтобы исправить то, что я пытался привязать флажок к списку, но это не сработало, мой код:

 SimpleCursorAdapter adapter =new SimpleCursorAdapter(this,R.layout.rating,cu,new String[]{"Title","Favorites"}, new int[]{R.id.text1,R.id.bt_rating},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        listv.setAdapter(adapter);

        adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder(){
               /** Binds the Cursor column defined by the specified index to the specified view */
               public boolean setViewValue(View view, Cursor cursor, int columnIndex){
                   if(view.getId() == R.id.bt_rating){

                      ((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;
               }
            });


 OnCheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) {
                 buttonView.setChecked(isChecked);
            }
        };

Мой xml-код содержимого строки моего списка:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

  <CheckBox
 android:id="@+id/bt_rating"
 android:focusable="false"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center_vertical"
 android:button="@android:drawable/btn_star"/>

<TextView

android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="@dimen/fsinlistview"

 />
</LinearLayout>

person Learning Android    schedule 06.01.2014    source источник
comment
vogella.com/tutorials/AndroidListView/   -  person Kanak Sony    schedule 06.01.2014
comment
к сожалению не нашел там то что мне нужно...буду продолжать поиски..все равно спасибо..   -  person Learning Android    schedule 06.01.2014


Ответы (2)


Похоже, проблема в вашем OnCheckedChangedListener. Если вы посмотрите на свой код, то увидите, что каждый флажок получает ссылку на один и тот же слушатель. Таким образом, когда вы устанавливаете флажок в одном поле, вы также устанавливаете флажок во всех других полях — и вы также не обновляете свои резервные данные.

Ваш OnCheckedChangedListener не должен обновлять состояние просмотра флажка - обратный вызов запускается, потому что состояние уже изменилось.

Поэтому вам нужно выполнить следующие шаги, когда пользователь устанавливает флажок:

  1. Выясните, какой элемент был проверен и как он соответствует вашим данным.
  2. Обновите свои данные, чтобы они соответствовали новому проверенному/непроверенному состоянию.
  3. Сообщите адаптеру об изменении данных/обновлении курсора.

Вы можете сделать это примерно так, пометив представление идентификатором строки, которую оно представляет:

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;
}

Затем в вашем слушателе вы можете обновить свою базу данных в соответствии с этим идентификатором:

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);
        }
    };

Наконец, вам нужно будет обновить адаптер курсора новым курсором после обновления строки базы данных:

 myAdapter.swapCursor(newCursor);

Вам придется настроить все это в соответствии с вашим кодом, но это должно дать вам представление о том, как вы можете решить эту проблему.

person Adam S    schedule 06.01.2014
comment
Хорошо, я это исправлю, но мой видоискатель не вызывается, потому что я поместил в него log.d, и он не вызывается. - person Learning Android; 07.01.2014
comment
также содержимое прослушивателя было добавлено непосредственно для проверки результата, что мне нужно сделать, это добавить изменения в мою базу данных; а почему вьюбиндер не вызывается? - person Learning Android; 07.01.2014
comment
Я не уверен в этом, извините - код для настройки связывателя представлений выглядит правильно. - person Adam S; 07.01.2014
comment
да, у меня были ошибки в адаптере, я не добавил в него bt_rating, поэтому сейчас он обращается к биндеру, но все равно получает неверные результаты, позже проверю причину, если Бог даст.. спасибо. - person Learning Android; 07.01.2014

В любом Listview представление используется повторно. Когда вы прокручиваете список, те, которые прокручиваются вверх и за пределы экрана, перерабатываются и используются с более новой информацией, которая появляется ниже.

Вам нужно отслеживать свои флажки с помощью разреженного массива. Отметьте индекс в массиве как проверенный/непроверенный, когда пользователь касается каждого из них. Затем вы устанавливаете состояние флажка на основе значения в массиве.

Вот пример кода из более старого приложения, которое выполняет как флажки «выбрать все», так и управляет всем списком отмеченных и неотмеченных. Это было для приложения посещаемости в классе, которое я написал, поэтому учителю было намного проще выбрать «ВСЕ», находясь в классе, а затем отменить выбор тех, кто не присутствовал.

У меня есть два флажка в этом списке и два разреженных массива, itemCheckedHere и itemCheckedLate (независимо от того, находится ли студент в классе или опоздал).

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;
    }

}

}

person Martin    schedule 06.01.2014
comment
Большое спасибо, Мартин, но этот код отличается от моего, я увижу его, если у меня закончатся решения :) - person Learning Android; 07.01.2014
comment
да, он отличается от вашего. Моя цель состояла не в том, чтобы написать для вас ваш код, а в том, чтобы предоставить пример того, как работать с флажками в списке. Если вы ищете код plug-n-play, который вы можете просто добавить в свой проект, мне нужно сначала предоставить вам мой счет PayPal, на который вы можете платить мне деньги за мои усилия. - person Martin; 08.01.2014