Получение проблемы при проверке динамически созданного флажка через просмотр списка

Я знаю, что этот вопрос уже задан другими членами, и решение также дается некоторыми членами, но дело в том, что я не нашел решения, подходящего для моего приложения. Я создаю приложение, в котором у меня есть экран, на котором будет отображаться динамическое listview с элементами списка, а также три текстовых поля (один для имени кандидата, а два других – для clockIn и clockOut, которые будут отображаться после выбора даты и времени на date time picker). Теперь моя проблема в том, что когда я проверяю первый флажок (у меня есть 15 имен кандидатов с флажками), автоматически проверяется 10-й checkbox, и это также происходит со 2-м и 11-м, 3-м и 12-м и так далее (наоборот, true). Я предоставляю свой class адаптера и элемент списка xml.

import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; import android.widget.Toast; import com.android.feedback.ListViewCheckBox; public class DemoAdapter extends ArrayAdapter{ private final List list; private final Activity context; LayoutInflater inflater; TextView CItv,COtv; static ViewHolder holder; View view; public DemoAdapter(Activity context, List list) { super(context, R.layout.test_listitems,list); // TODO Auto-generated constructor stub this.context = context; this.list = list; } static class ViewHolder { protected TextView text,CItv,COtv; protected CheckBox checkbox; } @Override public View getView(final int position, View convertView, ViewGroup parent) { view = null; // final ArrayList checkedItems = new ArrayList(); if (convertView == null) { inflater = context.getLayoutInflater(); view = inflater.inflate(R.layout.test_listitems, null); final ViewHolder viewHolder = new ViewHolder(); viewHolder.CItv = (TextView)view.findViewById(R.id.CITextView); viewHolder.COtv = (TextView)view.findViewById(R.id.COTextView); viewHolder.text = (TextView) view.findViewById(R.id.empTextView); viewHolder.checkbox = (CheckBox) view.findViewById(R.id.empCheckBox); viewHolder.checkbox .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){ Object o = getItemId(position+1); String keyword = o.toString(); Toast.makeText(getContext(), "You selected: " + keyword, 2000).show(); Toast.makeText(getContext(),ListViewCheckBox.DT_selected, 2000).show(); // holder.CItv.setText(ListViewCheckBox.DT_selected); // holder.COtv.setText(ListViewCheckBox.outDT_selected); } else{ Object o = getItemId(position+1); String keyword = o.toString(); //Toast.makeText(getContext(), "You unselected: " + keyword, 2000).show(); holder.CItv.refreshDrawableState(); holder.COtv.refreshDrawableState(); } } }); view.setTag(viewHolder); viewHolder.checkbox.setTag(list.get(position)); viewHolder.checkbox.setId(position); } else { view = convertView; ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position)); } holder = (ViewHolder) view.getTag(); holder.text.setText(list.get(position)); return view; } } 

и XML.

            

Пожалуйста, помогите мне избавиться от проблемы. (ListViewCheckBox – это class, который генерирует список и сохраняет значение даты и времени в переменных DT_selected и outDT_selected).

Я отредактировал свой ответ, поэтому общая информация находится наверху. Вы найдете фактический ответ на этот вопрос внизу …


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

  • Этап 1: Создание элемента для утилизации ( convertView равно null ):
    Это означает, что вы создаете макет и общее состояние, общее для всех элементов. Если у вас есть слушатели, вы добавили их сюда и разработали их таким образом, чтобы позже они могли реагировать на изменения позиции (когда они повторно используются). Так, например, задав позицию как тег на соответствующем представлении, чтобы слушатель мог поймать эту информацию и узнать, на каком элементе она работает. Вы не можете использовать представления для хранения данных. Поэтому, когда слушатель изменяет состояние элемента списка, вы должны сохранять эти данные (в массиве данных, в базе данных SQLite и т. Д.) И использовать его в фазе 2 .

  • Фаза 2: Состояние элемента настройки для заданной позиции:
    Вы устанавливаете визуальное состояние для элемента. Здесь необходимо установить все, что может измениться индивидуально для элемента (текст, состояние флажка, цвета и т. Д.). Не только то, что изменилось для текущего элемента, но могло быть изменено другим элементом. Таким образом вы убедитесь, что представление не используется в недопустимом состоянии, потому что оно повторно используется из другого элемента списка раньше.


Полученный ответ был удален / отредактирован, но предлагал реализовать getItemViewType и getViewTypeCount чтобы каждый элемент списка имел свой собственный тип вида. Теперь отредактированный ответ показывает, как решить проблему так, как она описана здесь.

Повторное выполнение getItemViewType и getViewTypeCount работает, но ваше явно неверное истолкование используется (сравните мой пример далее ниже и / или этот ответ ).

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

Если вы все-таки используете их, чтобы решить свою проблему, вы, вероятно, не поняли процесс, который я объяснил ранее. Таким образом, например, у вас есть 1000 элементов, и вы делаете взломанный тип вида, тогда вы создаете 1000 просмотров (иерархии), а, вероятно, 10, которые могут быть легко использованы повторно. Это не имеет большого значения, если у вас есть только 20 предметов или около того, но если вы используете эту технику для больших списков, вы просто теряете (драгоценную) память!

Вот пример:

 void getItemViewType(int position) { return isItemAtPositionSeperator(position) ? 1 : /* normal item */ 0; } void int getViewTypeCount() { return 2; // normal item and separator } void View getView(int position, View convertView, ViewGroup parent) { int type = getItemViewType(position); // phase 1: see my explanation if (convertView == null) { if (type == 0) { // setup your common item view - inflate it and set to convertView } else { // setup separator view - inflate it and set to convertView } } // phase 2: see my explanation if (type == 0) { // set the state of the common item view based on the position // rely on the fact that convertView contains the view hierarchy // you created in convertView == null && type == 0 } else { // set state of the separator based on the position // rely on the fact that convertView contains the view hierarchy // you created in convertView == null && type != 0 (else part) } return convertView; } 

Фактический ответ на вопрос …

Я знаю, в чем проблема, но не могу придумать элегантное решение прямо сейчас …

Ваша проблема в том, что вы устанавливаете прослушиватель кликов один раз с помощью viewHolder.checkbox.setOnCheckedChangeListener когда создается представление. Поэтому он перерабатывается / повторно используется для элементов при прокрутке, а поведение клика относится к неправильному элементу списка.

Старайтесь не жестко закодировать позицию, используя внешнюю final position . Попробуйте установить viewHolder.checkbox.setTag(position) перед return а затем используйте (Integer) buttonView.getTag() вместо position+1 . Таким образом, ваш переработанный вид сохранит фактическую позицию.

Когда вы нажимаете флажок, вы должны сохранять состояние в другом месте. Не полагайтесь на состояние пользовательского интерфейса для этого (потому что оно будет переработано). Поэтому перед return вызовите viewHolder.checkbox.setChecked(persistedState) .

Надеюсь, это имеет смысл, и вы получаете идею … 😉

Попробуй это,

Создайте class POJO, который будет поддерживать состояние выбранных элементов флажка, например,

 public class Model { private String name; private boolean selected; public Model(String name) { this.name = name; selected = false; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } } 

И это то, что вам нужно применить к getView() в адаптере.

 public View getView(int position, View convertView, ViewGroup parent) { checkBoxCounter = 0; checkBoxInitialized = 0; if (convertView == null) { final ViewHolder viewHolder = new ViewHolder(); LayoutInflater inflator = context.getLayoutInflater(); convertView = inflator.inflate(R.layout.main, null); viewHolder.text = (TextView) convertView.findViewById(R.id.label); viewHolder.checkbox = (CheckBox) convertView.findViewById(R.id.check); viewHolder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Model element = (Model) viewHolder.checkbox.getTag(); element.setSelected(buttonView.isChecked()); if(checkBoxCounter <= checkBoxInitialized){ // increment counter, when we scroll the List it execute onCheckedChanged everytime so by using this stuff we can maintain the state checkBoxCounter++; } else{ Model element = (Model) viewHolder.checkbox.getTag(); element.setSelected(buttonView.isChecked()); if(element.isSelected()) Toast.makeText(getContext(), "You selected "+ element.getName(), Toast.LENGTH_LONG).show(); else Toast.makeText(getContext(), "Not selected "+ element.getName(), Toast.LENGTH_LONG).show(); } } }); convertView.setTag(viewHolder); viewHolder.checkbox.setTag(list.get(position)); } else{ ((ViewHolder) convertView.getTag()).checkbox.setTag(list.get(position)); } ViewHolder viewHolder = (ViewHolder) convertView.getTag(); viewHolder.text.setText(list.get(position).getName()); viewHolder.checkbox.setChecked(list.get(position).isSelected()); return convertView; } 

Для дальнейшего изучения того, как это работает, вы можете взглянуть на полный пример . А также вы можете посмотреть, как работает ListView

UPDATE: Недавно я добавил решение для этого типа вопросов в блоге. ListView с проверкой прокрутки CheckBox

перейдите по ссылке ниже и перейдите к одиночному vrs Multiselection. здесь вы найдете очень хороший пример использования флажков в listview

(прокрутите вниз до Single vrs. Multiselection)

http://www.vogella.de/articles/AndroidListView/article.html

а также

Флажок в списке с пользовательской привязкой SimpleCurser

  • Как отключить прокрутку GridView в Android?
  • Использование VideoView для streamовой или прогрессивной загрузки видео
  • Как я могу вернуть значение из функции onResponse of Volley?
  • Ошибка таймаута волейбола
  • Обратный вызов fragmentа из диалогового windows
  • Как запретить Android делать снимок экрана, когда мое приложение переходит на задний план?
  • Google Cloud Messaging - сообщения, которые иногда не принимаются, пока не изменилось состояние сети
  • Инициализировать MapFragment программно с помощью Maps API v2
  • получение исключения "IllegalStateException: не удается выполнить это действие после onSaveInstanceState"
  • Single TextView с несколькими цветными текстами
  • Открыть страницу Facebook в приложении Facebook (если установлена) на Android
  • Interesting Posts

    Получение ошибки: не удалось найти class ‘android.app.AppOpsManager’, на который ссылается метод com.google.android.gms.common.GooglePlayServicesUtil.zza

    Что вызывает повреждение значков в Windows 7?

    Распределение стека, отступы и выравнивание

    C: указатель на массив фиксированного размера

    LINQ To Entities не распознает метод Last. В самом деле?

    Почему в Java нет множественного наследования, но допускается реализация нескольких интерфейсов?

    Заменить ось X собственными значениями

    Какие лицензии с открытым исходным кодом совместимы с iPhone Apple и его официальным магазином приложений?

    Excel в CSV с кодировкой UTF8

    Почему rails default_scope часто рекомендуют?

    Как сделать мой случай сравнения строк нечувствительным?

    Высокий экран DPI и Windows: как заставить программы вести себя как на экранах с низким разрешением?

    Драйвер принтера для Windows 7

    Восстановить неполные (?) Видеофайлы

    Chrome: как остановить перенаправление с http: // на https: //

    Давайте будем гением компьютера.