Android: CursorAdapter, ListView и CheckBox - PullRequest
       4

Android: CursorAdapter, ListView и CheckBox

16 голосов
/ 26 января 2011

У меня есть ListView с моим собственным макетом и CustomCursorAdapter. Каждый ряд имеет свой собственный флажок. Итак ... абсолютно ясно, что во время прокрутки флажки теряют свои состояния. Единственное, что я нашел, это Состояние сохранения Android-флажка в ListView с адаптером курсора , но ответа там нет. И еще один вопрос. У меня была такая же проблема с моим CustorArrayAdapter. Я решил эту проблему с помощью SparseBooleanArray, чтобы сохранить состояния флажков. Работает нормально, но каждая прокрутка вызываетCheckedChanged. Это нормально? Дело в том, что мой список отображает элементы сигнализации и периодические вызовы (из onCheckedChanged) запуска / остановки сигналов тревоги. Много бесполезных действий.

Ответы [ 8 ]

65 голосов
/ 26 января 2011

У меня была похожая проблема с моим ListView с CheckBox и что я сделал, чтобы избавиться от проблемы:

  • Создать ArrayList логического объекта для хранения состояния каждого CheckBox
  • Инициализирует элементы ArrayList значением по умолчанию false, что означает, что флажок еще не установлен.
  • Когда вы нажимаете на CheckBox. Установите проверку для состояния Checked / Unchecked и сохраните это значение в ArrayList.
  • Теперь установите эту позицию в CheckBox, используя метод setChecked ().

См. Этот фрагмент кода:

public class MyDataAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private ArrayList<String> list = new ArrayList<String>();
private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>();

// itemChecked will store the position of the checked items.

public MyDataAdapter(Context context, int layout, Cursor c, String[] from,
        int[] to) {
    super(context, layout, c, from, to);
    this.c = c;
    this.context = context;

    for (int i = 0; i < this.getCount(); i++) {
        itemChecked.add(i, false); // initializes all items value with false
    }
}

public View getView(final int pos, View inView, ViewGroup parent) {
    if (inView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inView = inflater.inflate(R.layout.your_layout_file, null);
    }

    final CheckBox cBox = (CheckBox) inView.findViewById(R.id.bcheck); // your
    // CheckBox
    cBox.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {

            CheckBox cb = (CheckBox) v.findViewById(R.id.your_checkbox_id);

            if (cb.isChecked()) {
                itemChecked.set(pos, true);
                // do some operations here
            } else if (!cb.isChecked()) {
                itemChecked.set(pos, false);
                // do some operations here
            }
        }
    });
    cBox.setChecked(itemChecked.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 inView;
}}
4 голосов
/ 01 февраля 2012

Я также столкнулся с подобной проблемой, поэтому после долгих чтений я решил эту проблему следующим образом:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview, null);
            holder = new ViewHolder();
            holder.nameView = (TextView)convertView.findViewById(R.id.textView1);
            holder.numberView = (TextView)convertView.findViewById(R.id.textView2);
            holder.cb = (CheckBox)convertView.findViewById(R.id.checkBox1);
            convertView.setTag(holder);                
        } else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.nameView.setText(mData.get(position).toString());
        holder.numberView.setText(mNumber.get(position).toString());
        holder.cb.setChecked(false);
        holder.cb.setTag(position);



        if(selected.indexOf(mNumber.get(position).toString()) >= 0)
        {

        holder.cb.setChecked(true);
        }

        return convertView;
    }

}

Вот что я делаю, что в getView () я снимаю все флажки и вручную проверяю те, которые мне нужно проверять в соответствии с textview, которому он соответствует. Таким образом, если пользователь прокрутит вниз после установки первого флажка, все флажки в представлении будут сняты, и если он снова прокрутится вверх, то также все флажки будут сняты, но затем тот, который он щелкнул ранее, будет снова проверен.

4 голосов
/ 26 января 2011

Есть несколько проблем с ListView, когда в нем есть проверяемые элементы.Я бы предложил следующую ссылку:

http://tokudu.com/2010/android-checkable-linear-layout/

Я думаю, что это близко к тому, что вы хотите.

2 голосов
/ 14 октября 2012

Я решил попробовать с методом setViewBinder. Состояние флажков сохраняется в SparseBooleanArray. Состояние чекбокса изменяется при нажатии самого флажка и всей ячейки.

Моя строка: | TextView | CheckBox |

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
//        ..
    private SparseBooleanArray checkedItems = new SparseBooleanArray(); //for storing item state

    startManagingCursor(cursor);
    String[] from = new String[] { dbAdapter.COLUMN_NAME, dbAdapter.COLUMN_CHECK };
    int[] to = new int[] { R.id.item_name, R.id.item_check };
    recordsAdapter = new SimpleCursorAdapter(this, R.layout.items, cursor, from, to);

    recordsAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
            if (columnIndex == 2) { //2 - R.id.item_check
                    final CheckBox cb = (CheckBox) view; 
                    final int rowID = cursor.getInt(0); //cursor.getInt(0) - _id from table

                    if (checkedItems.indexOfKey(rowID) >= 0) {  //checkedItems contains rowID?
                        cb.setChecked(checkedItems.get(rowID));
                    } else if (cursor.getInt(2) > 0) {          //cursor.getInt(2): 0 - false, 1 - true
                        checkedItems.append(rowID, true);
                        cb.setChecked(true);
                    } else {
                        cb.setChecked(false);
                    }

                    cb.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (checkedItems.indexOfKey(rowID) >= 0) {
                                checkedItems.put(rowID, !(checkedItems.get(rowID)));
                            } else {
                                checkedItems.append(rowID, true);
                            }
                            cb.setChecked(checkedItems.get(rowID));
                            dbAdapter.updateItem(rowID, checkedItems.get(rowID)?1:0);
                        }
                    });
                    return true;
            }
            return false;
        }
    });

    itemsList.setAdapter(recordsAdapter);
    itemsList.setOnItemClickListener(this);
//      ..
}

//if click on TextView of row - CheckBox of row is set/unset
@Override
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
    TextView tv = (TextView) view.findViewById(R.id.item_name);
    ViewGroup row = (ViewGroup) tv.getParent();
    CheckBox cb = (CheckBox) row.getChildAt(1);
    cb.performClick();
}
0 голосов
/ 12 мая 2016

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

listView.setChoiceMode (ListView.CHOICE_MODE_MULTIPLE);

0 голосов
/ 23 марта 2015

Возможно, вы опоздали, добавив Ответ Викаса Патидара - это полная реализация, использующая метод bindView для тех из вас, кто подает в суд на CursorAdapter:

@Override
        public void bindView(View view, Context context, Cursor cursor) {

            final ViewHolder holder = (ViewHolder) view.getTag();
            final int position = cursor.getPosition();
            String name = (cursor.getString(cursor.getColumnIndexOrThrow("NotificationDateFor")));
            String image = cursor.getString(cursor.getColumnIndexOrThrow("imageUri"));

             System.out.println("cursor.getPosition(test): "+cursor.getPosition());

            holder.nametext.setText(name);
        //  setImage(image, holder.iv); 


            holder.chk.setOnClickListener(new OnClickListener(){

                @Override
                public void onClick(View v) {

                        if (holder.chk.isChecked()) {
                            itemChecked.set(position, true);
                           System.out.println("cursor.getPosition(true): "+position);
                        } else if (!holder.chk.isChecked()) {
                            itemChecked.set(position, false);
                            System.out.println("cursor.getPosition(false): "+position);
                            // AddDelete
                        }   
                }               
            });

            holder.chk.setChecked(itemChecked.get(cursor.getPosition()));

        }

Примечание: final int position = cursor.getPosition(); значимо!

0 голосов
/ 21 сентября 2014

(sry, пока не могу комментировать) - что касается Ответа Vikas Patidar, который работает для меня - будьте внимательны при использовании асинхронной загрузки (например, при использовании Loader), потому что getCount в конструкторе адаптера будет равен нулю.1002 * В результате возникают ошибки индексации (поскольку ArrayList никогда не заполняется).Используйте SparseBooleanArray вместо ArrayList, и он также будет работать с асинхронной загрузкой.

0 голосов
/ 25 октября 2013

Я не могу понять, почему невозможно (как в HTML) определить ViewElement как массив в XML.Т.е.:

<CheckBox
    android:id="@+id/myCheckBox[]"
    android:focusable="false"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true" />

и сохранить значение в нем [true | false].Это сделало бы жизнь намного проще, вместо того, чтобы использовать сложный исходный текст.Также данные (т. Е. При переключении из альбомной в портретную) должны храниться на Android и не теряться.

Возможно, в API 117, версия toothscratch ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...