EditText en un adaptador de lista, cómo guardar el valor?

Por lo tanto, tengo un adaptador personalizado con dos campos EditText en cada fila.

He conseguido que la mayoría de las cosas funcionen correctamente, excepto guardando los valores dentro de ArrayList.

Este es el código que he hecho hasta ahora:

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) { if (!(position == (variantArrayList.size() - 1)) && holder.title != null) { holder.title.setText(variantArrayList.get(position).getVariantTitle()); final int finalPosition = position; holder.title.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { final EditText newVariant = (EditText) v; variantArrayList.get(finalPosition).setVariantTitle(newVariant.getText().toString()); } }); } } 

Así que esto realmente hace lo que quiero, se guarda el valor cuando el enfoque ha cambiado. Excepto por un problema, sólo guarda el valor cuando el foco ha cambiado.

Lo que es grande la mayor parte del tiempo, excepto cuando un usuario presiona un botón que hace desaparecer la vista completa. El enfoque nunca cambió, y el valor no se establece.

Así que estoy suponiendo que todos están pensando, sí, vamos a llamar a addOnTextChangedListener y adjuntar un TextWatcher, añadiendo algo como esto:

  holder.title.setText(variantArrayList.get(position).getVariantTitle()); final int finalPosition = position; final EditText holderTitle = (EditText) holder.title; if (holderTitle.getTag() != null) { final TextWatcher textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { variantArrayList.get(finalPosition).setVariantTitle(s.toString()); } @Override public void afterTextChanged(Editable s) { } }; holder.title.addTextChangedListener(textWatcher); holder.title.setTag(true); } 

No, eso tampoco funcionará. Claro que en realidad se guarda el valor, pero también se ensucia cosas cuando se desplaza desde el listview reutiliza la celda que piensa que el valor de una celda está en la otra celda y, a continuación, establece el valor de la ArrayList.

He intentado cosas diferentes, como comprobar el enfoque al cambiar valores y cosas, pero no funciona (por razones más o menos obvias).

¿Hay soluciones creativas para resolver esto?

ACTUALIZACIÓN (con más código):

El enfoque de TextWatcher como se sugiere:

Mi método getView (muchos otros códigos irrelevantes para este problema aquí):

 @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; IZUICartViewHolder holder; LayoutInflater inflater = ((Activity) context).getLayoutInflater(); if (v == null) { holder = new IZUICartViewHolder(); int type = getItemViewType(position); switch (type) { case TYPE_EDIT: v = inflater.inflate(R.layout.iz_ui_modify_product_cell, parent, false); holder.title = (EditText) v.findViewById(R.id.iz_prod_modify_variant_title); holder.title.setHint(addVariantPlaceholder); holder.deleteButton = v.findViewById(R.id.click_remove); holder.price = (EditText) v.findViewById(R.id.iz_prod_modify_price); holder.price.setHint(pricePlaceholder); holder.price.setText(String.valueOf(0.0)); break; } v.setTag(holder); } else { holder = (IZUICartViewHolder) v.getTag(); } hideDeleteButton(holder, position); holderTitleSavedOnScroll(position, holder); holderPriceSavedOnScroll(position, holder); v.setTag(holder); return v; } 

El método holderTitleSavedOnScroll

 private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) { if (!(position == (variantArrayList.size() - 1)) && holder.title != null) { holder.title.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { v.requestFocus(); } }); final int finalPosition = position; final EditText holderTitle = (EditText) holder.title; if (holderTitle != null) { holder.title.setText(variantArrayList.get(position).getVariantTitle()); } holderTitle.addTextChangedListener(new EditVariantTextWatcher(variantArrayList.get(finalPosition))); } } 

La clase TextWatcher:

 public class EditVariantTextWatcher implements TextWatcher { private IZUIProductVariantContainer variantContainer; protected EditVariantTextWatcher(IZUIProductVariantContainer variantContainer) { this.variantContainer = variantContainer; } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { variantContainer.setVariantTitle(s.toString()); } } 

2 Solutions collect form web for “EditText en un adaptador de lista, cómo guardar el valor?”

Esto se puede hacer mediante el uso cuidadoso de TextWatchers.

Incluya una referencia al TextWatcher actual en su ViewHolder. Cuando se recicla una vista, elimine el TextWatcher existente y añada uno nuevo, introducido en la posición actual.

Este es un ejemplo completo de trabajo, incluyendo el estado de ahorro para permitir la prueba de navegación lejos:

 public class EditTextListActivity extends ListActivity { private static final String SAVED_STATE_KEY = "saved_state_key"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EditTextAdapter editTextAdapter = new EditTextAdapter(this, R.layout.main); setListAdapter(editTextAdapter); // Restore our state, if there is any if (savedInstanceState != null) { List<String> savedStrings = savedInstanceState.getStringArrayList(SAVED_STATE_KEY); for (String savedString : savedStrings) editTextAdapter.add(new ListItem(savedString)); } else { // Add some empty items so that we can see it in action for (int i = 0; i < 30; i++) editTextAdapter.add(new ListItem("")); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); ArrayList<String> arrayList = new ArrayList<String>(); EditTextAdapter editTextAdapter = (EditTextAdapter) getListAdapter(); for (int i = 0; i < editTextAdapter.getCount(); i++) arrayList.add(editTextAdapter.getItem(i).string1); outState.putStringArrayList(SAVED_STATE_KEY, arrayList); } /** * The object we have a list of, probably more complex in your app */ static class ListItem { public String string1; ListItem(String string1) { this.string1 = string1; } } /** * ViewHolder which also tracks the TextWatcher for an EditText */ static class ViewHolder { public TextView textView; public EditText editText; public TextWatcher textWatcher; } class EditTextAdapter extends ArrayAdapter<ListItem> { EditTextAdapter(Context context, int resource) { super(context, android.R.layout.simple_list_item_single_choice); } @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; if (rowView == null) { // Not recycled, inflate a new view rowView = getLayoutInflater().inflate(R.layout.main, null); ViewHolder viewHolder = new ViewHolder(); viewHolder.textView = (TextView) rowView.findViewById(R.id.textview); viewHolder.editText = (EditText) rowView.findViewById(R.id.edittext1); rowView.setTag(viewHolder); } ViewHolder holder = (ViewHolder) rowView.getTag(); // Remove any existing TextWatcher that will be keyed to the wrong ListItem if (holder.textWatcher != null) holder.editText.removeTextChangedListener(holder.textWatcher); final ListItem listItem = getItem(position); // Keep a reference to the TextWatcher so that we can remove it later holder.textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { listItem.string1 = s.toString(); } @Override public void afterTextChanged(Editable s) { } }; holder.editText.addTextChangedListener(holder.textWatcher); holder.editText.setText(listItem.string1); holder.textView.setText(Integer.toString(position)); return rowView; } } } 

layout/main.xml :

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/textview" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" /> <EditText android:id="@+id/edittext1" android:layout_width="0dp" android:layout_height="?android:attr/listPreferredItemHeightSmall" android:layout_weight="2" android:inputType="text" /> <!-- This EditText is included to demonstrate problems with a naive approach. --> <EditText android:inputType="text" android:layout_width="0dp" android:layout_height="?android:attr/listPreferredItemHeightSmall" android:layout_weight="2" /> </LinearLayout> 

Bug conocido: un EditText perderá el foco inicial cuando el teclado aparece, vea esta respuesta para la discusión de ese problema.

Podemos ahorrar valor con la ayuda de TextWatcher

Mejor utilizar un modelo para almacenar y recuperar el valor de EditText.

 public class RowData { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } } 

Siguiente es TextWatcher Listener

 public class EditTextWatcher implements TextWatcher { private RowData data; public EditTextWatcher(RowData data) { this.data = data; } @Override public void afterTextChanged(Editable s) { data.setValue(s.toString()); } @Override public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } @Override public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } } 

Su Clase de Adaptador

  public class YourAdapter extends ArrayAdapter<RowData> { private ArrayList<RowData> data; private Context context; public YourAdapter(Context context, ArrayList<RowData> data) { super(context, 0, data); this.data = data; } @Override public View getView(final int position, View convertView, ViewGroup parent) { View v = convertView; final RowData row = data.get(position); final EditText edittext = (EditText) v.findViewById(R.id.edittext); if (edittext != null) edittext.setText(row.getValue()); edittext.addTextChangedListener(new EditTextWatcher(row)); ///////Your Code ///// } } 

// edittext.addTextChangedListener(new EditTextWatcher(row)); Esta línea almacenará los datos para cada EditText, e incluso si se desplaza el ListView entonces al crear la célula se establecerá el valor de Model (RowData)

Prueba de esta manera, Espero que esto te ayude.

  • Mostrar siempre la barra de desplazamiento para ListView
  • Cambiar la altura del divisor de listview dinámicamente?
  • Cómo definir ColorStateList para TextView?
  • Listview setItemChecked no funciona
  • Stick Android ListView "categorías" para arriba
  • Android ListView con estilo como iPhone agrupado UITableView
  • Cómo construir un diseño complejo en android con múltiples vistas de lista
  • Problema al agregar pie de página a ListView
  • ¿Hay alguna manera de saber cuántos elementos están mostrando en una vista de lista?
  • Android: AbsListView.OnScrollListener SCROLL_STATE_IDLE no se llama después de SCROLL_STATE_TOUCH_SCROLL (versión 2.1)
  • uiautomator - no puede obtener ListView para desplazarse como validar el texto en cada elemento de la lista. sólo falla cuando golpeo el último elemento en la pantalla
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.