#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, массив, база данных и т. Д.). Поначалу кажется немного неудобным, но вы будете понимать это все больше и больше.