Я знаю, что этот вопрос уже задают другие участники, и некоторые участники также предлагают решение, но дело в том, что я не нашел ни одного решения, подходящего для моего приложения. Я создаю приложение, в котором у меня есть экран, на котором будет отображаться динамический список с элементами списка, флажком и тремя текстовыми окнами (одно для имени кандидата, а два других - для времени clockIn и clockOut, которое будет отображаться после выбора выбор даты и времени по дате) .Теперь моя проблема в том, что когда я устанавливаю первый флажок (у меня есть 15 имен кандидатов с флажками), автоматически проверяется 10-й флажок, и это также происходит со 2-м и 11-м, 3-м и 12-м и т. д. (Верно и обратное). Здесь я предоставляю свой класс адаптера и элемент списка 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<String>{
private final List<String> list;
private final Activity context;
LayoutInflater inflater;
TextView CItv,COtv;
static ViewHolder holder;
View view;
public DemoAdapter(Activity context, List<String> 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<Integer> checkedItems = new ArrayList<Integer>();
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.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1,2,3">
<TableRow >
<CheckBox android:text=" " android:id="@+id/empCheckBox"
style="@style/Check" android:textColor="#000000"
android:textSize="12dp"
android:layout_weight="1"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/empTextView"
style="@style/CICOTextView"
android:layout_weight="2"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/CITextView"
style="@style/CICOTextView"
android:text=""
android:layout_weight="3"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/COTextView"
style="@style/CICOTextView"
android:text=""
android:layout_weight="4"/>
</TableRow>
</TableLayout>
</LinearLayout>
Пожалуйста, помогите мне избавиться от проблемы. (ListViewCheckBox - это класс, который генерирует список и сохраняет значение даты и времени в переменных DT_selected и outDT_selected).
Я отредактировал свой ответ , чтобы общая информация располагалась сверху. Вы найдете актуальный ответ на этот вопрос внизу ...
Вот реальная идея и процесс переработки, чтобы вы могли выяснить, что не так с вашей реализацией и идеей getView
(и, возможно, с другими, когда они найдут этот вопрос и ответ). Ниже приведен пример кода, просто игнорируйте часть типа, так как это дополнительная информация.
Этап 1. Создание элемента для переработки (convertView
- null
):
Это означает, что вы создаете макет и общее состояние, которое является общим для всех элементов. Если у вас есть слушатели, вы должны добавить их сюда и спроектировать так, чтобы они могли реагировать на изменения позиции (когда они используются повторно) позже. Например, установив позицию в качестве тега в соответствующем представлении, чтобы слушатель мог уловить эту информацию и узнать, над каким элементом он работает в данный момент. Вы не можете использовать представления для хранения данных. Поэтому, когда слушатель меняет состояние элемента списка, вы должны сохранить эти данные (в массиве данных, в базе данных SQLite и т. Д.) И использовать их в фаза 2 .
Этап 2: состояние элемента настройки для заданной позиции:
Вы задаете визуальное состояние для элемента. Все, что может измениться индивидуально для элемента (текст, состояние флажка, цвета и т. Д.), Должно быть установлено здесь. Не только то, что изменилось для текущего элемента, но могло быть изменено другим элементом. Таким образом, вы убедитесь, что представление не используется в недопустимом состоянии , потому что оно ранее использовалось из другого элемента списка.
Признанный ответ был удален / отредактирован, но предлагалось реализовать getItemViewType
и getViewTypeCount
, чтобы у каждого элемента списка был свой тип представления. Отредактированный ответ теперь показывает, как решить проблему, как это описано здесь.
Повторное воплощение getItemViewType
и getViewTypeCount
работает, но вы явно неверно истолковываете его использование (сравните мой пример ниже и / или этот ответ ).
Эти два способа существуют для использования двух (или более) элементов списка, которые полностью отличаются друг от друга (например, элемент общего списка и разделитель, который содержит только заголовок), и чтобы не избежать повторного использования представления, которое можно использовать повторно. .
1136 Если вы все равно используете их для решения своей проблемы, вы, вероятно, не поняли процесс, который я объяснил ранее. Так, например у вас есть 1000 элементов, и вы выполняете тип представления hack , затем вы создаете 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
. Таким образом, ваш переработанный вид сохранит фактическую позицию.
Когда вы устанавливаете флажок, вы должны сохранять состояние в другом месте. Не полагайтесь на состояние пользовательского интерфейса для этого (потому что оно будет переработано). Так что звоните viewHolder.checkbox.setChecked(persistedState)
до return
.
Я надеюсь, что это имеет смысл, и вы поняли ...; -)