Дублированная ссылка на макет в виде списка

#android #listview #duplicates #custom-adapter

#Android #listview #дубликаты #пользовательский адаптер

Вопрос:

С моим listview происходит действительно странная вещь. Я создаю ListView с кнопками и EditText.

Он расположен следующим образом: [Кнопка] [EditText] [Кнопка], кнопки работают как «инкремент» и «декремент», обновляя числовое значение EditText в 1 единице за клик. Проблема в том, что когда я нажимаю кнопку, почти каждый раз, когда изменяется текст редактирования другого элемента представления списка (также изменяется текст редактирования выбранного элемента). И если я нажму на кнопку этого ошибочного измененного элемента, он также изменит EditText первого. Они в основном имеют одинаковые ссылки на кнопки и EditText, хотя у них есть текстовые представления с данными, и эти данные у них разные.

Для достижения этой цели я создал и пользовательский адаптер:

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

        if(convertView == null) {
            convertView = mInflater.inflate(R.layout.lastproduct_row, null);
            holder = new ViewHolder();
            holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
            holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
            holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade);                

            TextView tv;

            holder.tvList = new TextView[PRODUCTROW_INT_KEY.length];

            for(int i = 0; i < PRODUCTROW_INT_KEY.length; i  ) {
                tv = (TextView) convertView.findViewById(PRODUCTROW_INT_KEY[i]);
                holder.tvList[i] = tv;                  
            }

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

        HashMap<String, String> hm = productsList.get(position);
        String key = hm.get(CODIGO_KEY);

        for(int i = 0; i < PRODUCTROW_INT_KEY.length; i  ) {
            holder.tvList[i].setText(hm.get(PRODUCTROW_STR_KEY[i]));
        }

        holder.btnAddQtd.setTag(key QTD_FLAG ADD_ACTION);
        holder.btnSubQtd.setTag(key QTD_FLAG SUB_ACTION);
        holder.btnAddQtd.setOnClickListener(handle);
        holder.btnSubQtd.setOnClickListener(handle);

        if(novosEstoques.containsKey(key)) {
            holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
        }

        return convertView;
    }

    class ViewHolder {
        private TextView []tvList;
        private Button btnAddQtd, btnSubQtd;
        private Button btnAddQtVol, btnSubQtVol;
        private EditText etQuantidade, etQtVolume;
    }
  

Я добавил к кнопкам слушателей onClick, установив их теги с моим идентификатором элемента ListView (объединенным с другой информацией). Затем в моем прослушивателе событий я просто получаю родительский вид кнопки (LinearLayout) и получаю из него EditText с помощью getViewAt():

     @Override
    public void onClick(View v) {
        String tag = (String) v.getTag();

        if(tag.contains(QTD_FLAG)) {
            String []info = ((String) v.getTag()).split(QTD_FLAG);
            float qtd;
            LinearLayout ll = (LinearLayout) v.getParent();
            ll.setBackgroundColor(Color.rgb(0, 128, 30));
            EditText et = (EditText) ll.getChildAt(2);

            qtd = Float.parseFloat(et.getText().toString().replace(",", "."));

            if(info[1].equals(ADD_ACTION)) {
                qtd  ;

            }
            else if(info[1].equals(SUB_ACTION)) {
                if(qtd > 0)
                    qtd--;
            }

            Log.d("TESTE", "MODIFICAR KEY = " info[0]);
            et.setText(qtd "");
        }           
    }
  

Я использую setBackgroundColor в этом примере, чтобы подтвердить, что экземпляр LinearLayout дублируется в lisView. Когда я нажимаю кнопку, она отображается в 2 разных элементах списка.

Кто-нибудь может указать мне, что может быть причиной этого? Я нашел людей с дублированным элементом ListView, я не знаю, мой ли это случай, потому что у меня есть TextView внутри моего ListView, и они не равны, только часть LinearLayout с кнопками и EditText является «общей».


Я вношу некоторые изменения в свой метод getView, и теперь он работает! Кажется, что каждый раз, когда вызывается метод getView, я вообще не гарантирую, что мои EditTexts будут заполнены правильно, и я этого не осознавал. Поэтому при каждом вызове getView я устанавливаю значение EditText, если пользователь редактирует значение ET, я сохраняю его в HashMap для восстановления в getView, если в HashMap нет записи для данного EditText, тогда я устанавливаю для него значение по умолчанию (ноль):

     ...
    if(convertView == null) {
            holder = new ViewHolder();
            holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
            holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
            holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade); 

            //Now it is easier to get etQuantidade reference in button
            //click handle, I just have to do:
            //    public onClick(View v) {
            //        EditText etButtonAssociated = (EditText) v.getTag();
            //        ...
            //    }
            holder.btnAddQtd.setTag(holder.etQuantidade);
            holder.btnSubQtd.setTag(holder.etQuantidade);

            holder.btnAddQtd.setOnClickListener(handle);
            holder.btnSubQtd.setOnClickListener(handle);
            ...
    }
    else {
        ...
    }
    holder.etQuantidade.setTag(key);

    if(novosEstoques.containsKey(key)) {
        holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
    }
    else {
        holder.etQuantidade.setText("0");
    }

    return convertView;
  

Комментарии:

1. где вы получаете «et» в onClick?

2. Спасибо, что присоединились к StackOverflow. Ваш вопрос очень хорошо составлен, поэтому давайте посмотрим, как получить ответ для вас. 🙂

3. @mozarty Я делаю это с помощью этой строки: EditText et = (EditText) ll.getChildAt(2);

Ответ №1:

Израиль,

После просмотра вашего кода мне стало интересно, какое решение о реализации вы приняли. Поскольку каждая кнопка «привязана» к определенному EditText , рассматривали ли вы возможность установки Tag Buttons для них значения EditText ? Это Tag может быть любой Object , включая элемент пользовательского интерфейса. Это особенно полезно для динамических элементов пользовательского интерфейса, таких как список, заполненный во время выполнения.

Поскольку это обрабатывается в вашем Adapter , вам не придется беспокоиться о дублирующихся родителях и тому подобном. Кроме того, вы могли бы избежать необходимости беспокоиться о «поиске» элемента управления в вашем onClick() , потому что он у вас будет (это тег). Я не совсем уверен, что нужно вашему проекту, но это кажется потенциально жизнеспособным решением, если только они не нужны вам Buttons для выполнения других задач.

Внимание: Просто убедитесь, что вы удалили ссылки на теги EditText , когда закончите. В противном случае вы рискуете потерять часть памяти.

Нечеткая логика

Комментарии:

1. Привет, чувак, спасибо за советы! Это улучшает код, но дублированная ссылка остается неизменной =/ Я помещаю свой EditText в качестве тега кнопки и помещаю идентификатор в качестве тега EditText (мне нужно, чтобы этот идентификатор сохранялся для каждого элемента ListView). И когда я начинаю свою деятельность и изменяю какое-либо значение EditText (обычно первое значение ET), тогда другое значение также изменяет его значение (обычно элемент ET, который находится за пределами текущего представления при редактировании первого). Поэтому я помещаю свой идентификатор в качестве тега в каждый EditText и показываю его в тосте при его редактировании. К моему удивлению, идентификаторы разные! Поэтому я думаю, что проблема где-то в моем адаптере.

2. Похоже на то. По крайней мере, это дает вам представление о том, с чего начать. Я очень быстро просмотрю ваш адаптер… посмотрите, выделяется ли что-нибудь.

3. Израиль, не могли бы вы опубликовать свой обновленный код? В частности, ваши getView () и onClick()?

4. О, я понял! Это кажется немного грязным, но я заставляю это работать, я думаю, что это обычный способ сделать это. Я обновлю вопрос улучшением, которое заставит его работать.

5. Рад, что вы нашли решение. Это не «грязный», это стандартный шаблон проектирования MVC (модель, представление, контроллер). Ваше представление (список) не знает и не заботится о том, откуда поступают данные, поэтому оно не «привязано» таким же образом. Ваш адаптер применяет вашу модель (данные) к представлению (списку). Но (Модель) фактически управляется какой-либо другой структурой (Hashmap, массив, база данных и т. Д.). Поначалу кажется немного неудобным, но вы будете понимать это все больше и больше.