Подтвердить что ты не робот

EditText теряет содержимое при прокрутке в ListView

У меня есть элемент списка с EditText в нем, я не знаю, сколько предметов там будет. У меня проблема при вводе некоторого текста в EditText, а затем прокрутка вниз по списку ListView после того, как я снова прокручиваю текст, нет текста в моем первом EditText или есть какой-то текст из другого EditText из ListView.

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

Как определить правильное положение вида в ListView?

Например:

Если у меня есть 10 элементов в ListView, и только 5 из них в настоящее время видны. Возвращаемое положение адаптера от 0 до 4... это нормально. Когда я прокручиваю позицию позиции 6, 0... wtf? и я теряю данные из массива в позиции 0:)

Im, используя ArrayAdapter.

Пожалуйста, помогите.

Вот код:

public View getView(int position, View convertView, ViewGroup parent) {

    tmp_position = position;

    if (convertView == null) {

        holder = new ViewHolder();

        LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.element_in_game, null);

        holder.scoreToUpdate = (EditText) convertView
                .findViewById(R.id.elementUpdateScore);

        holder.scoreToUpdate.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start,
                    int before, int count) {
                scoresToUpdate[tmp_position] = s.toString();
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start,
                    int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        initScoresToUpdateEditTexts(holder.scoreToUpdate, hint);

        convertView.setTag(holder);

    } else {

        holder = (ViewHolder) convertView.getTag();

        holder.scoreToUpdate.setText(scoresToUpdate[tmp_position]);

    }

    return convertView;
}
4b9b3361

Ответ 1

вы должны попробовать таким образом, как показано ниже:

if (convertView == null) {

        holder = new ViewHolder();

        LayoutInflater vi = (LayoutInflater)    
        getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.element_in_game, null);

        holder.scoreToUpdate = (EditText) convertView
                .findViewById(R.id.elementUpdateScore);


        convertView.setTag(holder);

    } else {

        holder = (ViewHolder) convertView.getTag();

    }
   //binding data from array list
   holder.scoreToUpdate.setText(scoresToUpdate[position]);
   holder.scoreToUpdate.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start,
                    int before, int count) {
                //setting data to array, when changed
                scoresToUpdate[position] = s.toString();
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start,
                    int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

    return convertView;
}

Объяснение: Повторное использование ListView, фактически стирает все данные, связываясь с его элементом Row, когда выходите из поля зрения. Таким образом, каждая новая строка входит в видение из любого направления, необходимое для привязки данных снова. Кроме того, при изменении текста EditText вы должны сохранять значения и в некоторой структуре данных, поэтому в дальнейшем после связывания данных строк вы можете извлекать данные для позиции. Вы можете использовать массив ArrayList для хранения данных edittext, а также можете использовать для привязки данных.

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

Ответ 2

вместо этого вы можете использовать setOnFocusChangeListener. в моем случае у меня есть расширяемый список, и он кажется хорошим:) например:

holder.count.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                EditText et =(EditText)v.findViewById(R.id.txtCount);
                myList.get(parentPos).put(childPos,
                        et.getText().toString().trim());
            }
        }
    });

Ответ 3

Если у вас будет только ~ 10 строк, не беспокойтесь о ListView. Просто поместите их в вертикальный LinearLayout и оберните это в ScrollView, и это сэкономит вам некоторую головную боль.

Если у вас будет десятки или сотни строк, я предлагаю вам придумать лучшую парадигму UX, чем EditText виджеты в строках ListView.

Все, что говорится, похоже, что вы не правильно обрабатываете свою переработку строк или не знаете, что строки будут переработаны. Если у вас есть 10 элементов в вашем ListAdapter, и у вас есть только место для отображения 5 строк с помощью виджета EditText, вы не должны заканчивать 10 видми EditText, когда пользователь прокручивается вниз. Вы должны набрать 5-7 - те, которые есть на экране, и, возможно, еще один или два для повторного использования, когда пользователь прокручивается дальше.

Этот бесплатный фрагмент из одной из моих книг проходит процесс создания пользовательских подклассов ArrayAdapter и работа рециркуляции. Он также охватывает наличие интерактивной строки, используя RatingBar для ввода пользователем. Это намного проще, чем EditText, потому что все, о чем вам нужно беспокоиться, - это события щелчка. Вы можете попытаться расширить эту технику с помощью EditText виджетов и TextWatcher слушателей, но я не поклонник.

Ответ 4

У меня была проблема, которую я решил. Каждая строка моего ListView имеет другой вид (он содержит разные элементы управления. EditView, ImageView, TextView). Я хочу, чтобы данные, введенные или выбранные в этих элементах управления, сохранялись, даже когда элемент управления прокручивается с экрана. Решением, которое я использовал, было реализовать следующие методы в ArrayAdapter следующим образом:

public int getViewTypeCount() {
    return getCount();
}

public int getItemViewType(int position) {
    return position;
}

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

public View getView(int position, View convertView, ViewGroup parent) {

  if (convertView != null)
    return convertView;
  else
  // create new view
}

Ответ 5

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

fooobar.com/questions/435561/...

Это мой первый пост, но я надеюсь, что он будет достаточно полезен.

Ответ 6

Из краткого описания вашего кода, похоже, вы боретесь с рециклистом. Когда вы переходите из позиции 1 в позицию 20 в списке, он не создает 20 разных экземпляров вида списка. Вместо этого он имеет 7 или 8. Когда один прокручивается с экрана, он добавляется в ресайлер, а затем отправляется методу getView в качестве параметра convertView, поэтому вы можете повторно заполнить его новыми данными, а не расточительно создавать новый вид.

Традиционно используется шаблон ViewHolder для хранения подсмотров элемента списка (textview, imageview и т.д.), а не данных (настройка и получение оценки внутри держателя). Что происходит, когда вы устанавливаете значение на ноль при нулевой позиции, прокрутите вниз до 6-го элемента на экране с 5 элементами, 0-й элемент снова будет использоваться для позиции 6, и он вытащит существующее значение из держателя, прикрепленного к этому элементу listitem (в данном случае, 0)

Простой ответ: не храните данные о местоположении в держателе! Поместите его во внешний массив или хэш-таблицу где-нибудь.

Ответ 7

Лучше всего создать EditText во время выполнения и установить его id в качестве аргумента позиции

метода getView(). поэтому теперь, когда текст добавляется, сохраните его в переменной Вектор (класс

), а в методе getView, основанном на переменной позиции, задается текст (который вы можете

получить использование метода elementAt() вектора) соответствующего EditText.

и не забудьте добавить этот EditText к завышенному представлению.

Ответ 8

Этот код поможет вам

private class EfficientAdapter extends BaseAdapter {
        private LayoutInflater mInflater;
        private String[] attitude_names;
        public String[] attitude_values;
        private String name;
public static HashMap<Integer,String> myList=new HashMap<Integer,String>();

        public EfficientAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
            attitude_names = context.getResources().getStringArray(R.array.COMP_ATTITUDE_NAME);
            attitude_values = new String[attitude_names.length];
        }
// initialize myList
for(int i=0;i<attitude_names.length;i++)
{
   myList.put(i,"");
}


        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            final ViewHolder holder;

            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.addcomp_attitude_row, null);

                holder = new ViewHolder();
                holder.Attitude_Name = (TextView) convertView.findViewById(R.id.addcomp_att_name);
                holder.Attitude_Value = (EditText) convertView.findViewById(R.id.addcomp_att_value);
                holder.Attitude_Value.addTextChangedListener(new TextWatcher()
                    {
                        public void afterTextChanged(Editable edt) 
                        {
                             myList.put(pos,s.toString.trim());
                            attitude_values[holder.ref] = edt.toString();
                        }

                        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}

                        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
                            //attitude_values[ref] = Attitude_Value.getText().toString();
                        }
                    });

                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }


            holder.ref=position;
            holder.Attitude_Name.setText(attitude_names[position]);
            holder.Attitude_Value.setHint(attitude_names[position]);
            holder.Attitude_Value.setText(myList.get(position));




            return convertView;
        }

        class ViewHolder {
            TextView Attitude_Name;
            EditText Attitude_Value; 
            int ref;



        }

        @Override
        public int getCount() {
            return attitude_names.length;
        }
    }

Здесь я включил объект HashMap, который будет следить за тем, что EditText содержит значение. И когда вы прокручиваете список, он будет отображаться снова, вызвав его метод getView.

В этом коде, когда вы сначала загружаете listview, все ваши edittext будут без text.once, вы вводите какой-то текст, это будет отмечено в myList.So, когда вы снова визуализируете список, ваш текст будет предотвращен.

Ответ 9

Пройдите по проверке convertView == null и это еще раз. У вас будет худшая производительность, но она отключит рециркуляцию.

Ответ 10

Мой адаптер расширяет BaseAdapter, и у меня была аналогичная ситуация, когда bickster имел место, где у меня было представление списка, в котором были разные взгляды (динамическая форма, подобная ситуации) и необходимо сохранить данные. Мое представление списка не было слишком большим, поэтому повторное использование вида не было большим ресурсом, потребляемым в моем случае и, следовательно, простым

if (convertView != null) return convertView;

в начале getView было достаточно для меня. Не уверен, насколько эффективно это решение, но это то, что я искал.

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

Ответ 11

Сначала объявите переменную-член String[] или List<String> (внутри класса вне getView()) для хранения входного текста из объекта EditText и запишите текст в addTextChangeListener(), который вы установили для объекта EditText.

    viewHolder.editText.removeTextChangedListener(viewHolder.textWatcher);

    viewHolder.textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        }

        @Override
        public void afterTextChanged(Editable editable) {
            mInputs[position] = editable.toString();            //record input

            viewHolder.editText.setSelection(viewHolder.editText.getText().length());       //set cursor to the end
        }
    };

    viewHolder.editText.addTextChangedListener(viewHolder.textWatcher);
    viewHolder.editText.setText(mInputs[position]);

private class ViewHolder {
    EditText editText;
    TextWatcher textWatcher;

    public ViewHolder(View itemView) {
        editText = itemView.findViewById(R.id.main_editText);
    }
}