Возникла проблема при проверке динамически сгенерированного флажка через list view

Я знаю, что этот вопрос уже задают другие участники, и некоторые участники также предлагают решение, но дело в том, что я не нашел ни одного решения, подходящего для моего приложения. Я создаю приложение, в котором у меня есть экран, на котором будет отображаться динамический список с элементами списка, флажком и тремя текстовыми окнами (одно для имени кандидата, а два других - для времени 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).

22
задан himanshu 12 October 2011 в 10:19
поделиться

1 ответ

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


Вот реальная идея и процесс переработки, чтобы вы могли выяснить, что не так с вашей реализацией и идеей 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.

Я надеюсь, что это имеет смысл, и вы поняли ...; -)

31
ответ дан 29 November 2019 в 04:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: