EditText теряет содержимое при прокрутке в ListView - PullRequest
12 голосов
/ 08 января 2012

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

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

Как определить правильную позицию представления в ListView?

Например:

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

Я использую 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;
}

Ответы [ 10 ]

16 голосов
/ 19 января 2012

Вы должны попробовать следующим образом:

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 Item, когда они выходят из поля зрения. Таким образом, каждая новая строка появляется в любом направлении, в котором вам нужно снова связать данные. Кроме того, когда изменяется текст EditText, вы должны сохранять значения также в некоторой структуре данных, чтобы позже снова связать данные строки, вы можете извлечь данные для позиции. Вы можете использовать массив ArrayList для хранения данных редактирования текста, а также для связывания данных.

Аналогичное поведение используется в Recyclerview Adapter, за логикой вам необходимо знать о привязке данных к строкам данных адаптеров.

12 голосов
/ 21 октября 2013

вместо этого вы можете использовать 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());
            }
        }
    });
5 голосов
/ 08 января 2012

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

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

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

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

4 голосов
/ 13 ноября 2013

У меня была связанная проблема, которую я решил. Каждая строка моего 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
}
2 голосов
/ 09 ноября 2012

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

https://stackoverflow.com/a/13312282/1812518

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

1 голос
/ 19 января 2012

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

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

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

0 голосов
/ 15 марта 2017

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

if (convertView != null) return convertView;

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

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

0 голосов
/ 15 июня 2012

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

0 голосов
/ 18 февраля 2012

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

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.

В этом коде, когда вы сначала загружаете просмотр списка, весь ваш текст редактирования будет без текста. Как только вы введете какой-то текст, он будет отмечен в myList. Поэтому, когда вы снова визуализируете список, ваш текст будет заблокирован.

0 голосов
/ 17 января 2012

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

из getView() метода.так что теперь, когда текст добавлен, сохраните его в переменной Vector (переменная class

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

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

и не забудьте добавить этот EditText в раздутый вид.

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