EditText pierde contenido en desplazamiento en ListView

Tengo un elemento de la lista con EditText, no sé cuántos elementos habrá. Tengo un problema cuando ingreso un texto en EditText, y luego me desplazo hacia abajo en un ListView, después de volver a desplazarme hacia arriba, no aparece texto en mi primer EditText, o hay texto de EditText en ListView.

He intentado con TextWatcher y guardo datos en una matriz, pero hay problemas porque la posición de vista devuelta en ListView no siempre es correcta, así que perdí algunos datos de la matriz. -.-

¿Cómo detectar la posición correcta de la vista en ListView?

Por ejemplo:

Si tengo 10 elementos en ListView, y solo 5 de ellos están actualmente visibles. Posición de retorno del adaptador de 0 a 4 … eso está bien. Cuando me desplazo hacia abajo, la posición del elemento 6 es 0 … wtf? y pierdo datos de la matriz en la posición 0 🙂

Estoy usando ArrayAdapter.

Por favor ayuda.

Aquí hay un código:

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; } 

deberías intentarlo de la siguiente manera:

 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; } 

Explicación: El comportamiento de reciclaje de ListView, en realidad borra todos los datos vinculados con su elemento de fila, cuando se pierde la visión. Por lo tanto, cada nueva fila entrará en la visión desde cualquier dirección que necesite para vincular los datos nuevamente. Además, cuando se modifique el texto de EditText, también debe mantener los valores en alguna estructura de datos, de modo que más adelante, el enlace de datos en fila puede extraer datos para la posición. Puede usar ArrayList para mantener datos de texto de edición, y también puede usar para enlazar datos.

Uso de comportamiento similar en Recyclerview Adapter, detrás de la lógica que necesita saber sobre el enlace de datos de fila de datos de adaptadores.

puede usar setOnFocusChangeListener en su lugar. en mi caso tengo List ampliable y me parece bien 🙂 así:

 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()); } } }); 

Si solo tiene ~ 10 filas, no se moleste con ListView . Simplemente colóquelos en un LinearLayout vertical y envuélvalo en un ScrollView , y le ahorrará algo de dolor de cabeza.

Si vas a tener docenas o cientos de filas, te sugiero que encuentres un mejor paradigma UX que los widgets EditText en las filas de ListView .

Dicho todo esto, parece que no está manejando su reciclaje de hileras correctamente, o no sabe que las hileras se reciclan. Si tiene 10 elementos en su ListAdapter y solo tiene espacio para mostrar 5 filas con los widgets EditText , no debería terminar con 10 widgets EditText cuando el usuario se desplaza hacia abajo. Deberías terminar con 5-7: los de la pantalla, y quizás uno o dos más para reciclar cuando el usuario se desplaza a continuación.

Este extracto gratuito de uno de mis libros pasa por el proceso de crear subclases personalizadas de ArrayAdapter y hacer que el reciclaje funcione. También cubre tener una fila interactiva, usando una RatingBar de RatingBar para la entrada del usuario. Eso es mucho más fácil que un EditText , porque todo lo que tiene que preocuparse es hacer clic en eventos. Le invitamos a tratar de ampliar esa técnica con los widgets TextWatcher y los oyentes TextWatcher , pero no soy un fanático.

Tenía un problema relacionado que resolví. Cada fila de mi ListView tiene una vista diferente (contiene controles diferentes: EditView, ImageView, TextView). Quiero que los datos ingresados ​​o seleccionados en esos controles persistan incluso cuando el control se desplaza fuera de la pantalla. La solución que utilicé fue implementar los siguientes métodos en ArrayAdapter esta manera:

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

Esto asegurará que cuando se getView() pase la misma instancia de View que se devolvió desde getView() en la primera llamada.

 public View getView(int position, View convertView, ViewGroup parent) { if (convertView != null) return convertView; else // create new view } 

Recientemente busqué una solución similar y descubrí que usar el textChangeListener NO es el mejor enfoque. Respondí una pregunta relacionada aquí:

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

Es mi primer mensaje, pero espero que sea bastante útil.

A partir de una breve revisión de tu código, parece que te estás enfrentando al reciclador. Cuando se desplaza de la posición 1 a la posición 20 en una vista de lista, no crea 20 instancias diferentes de la vista del elemento de vista de lista. En cambio, tiene 7 u 8: cuando uno se desplaza fuera de la pantalla, se agrega a la recicladora y luego se envía al método getView como parámetro convertView, de modo que puede volver a llenarlo con nuevos datos en lugar de crear una nueva vista .

Tradicionalmente, uno usa el patrón ViewHolder para guardar las subvistas de un elemento de la lista (textview, imageview, etc.), no data (establecer y obtener el puntaje desde el titular) – Lo que sucede es que establece el valor en cero en la posición cero, desplazarse hacia abajo hasta el 6º elemento en una pantalla de 5 elementos, el 0º elemento se vuelve a utilizar para la posición 6, y extrae el valor existente del titular adjunto a ese elemento de lista (en este caso, un 0)

Respuesta simple: ¡No almacene datos específicos de posición en el soporte! Stash en una matriz externa o hashtable en alguna parte.

Una mejor manera es crear EditText en tiempo de ejecución y establecer su id como argumento de posición

del método getView() así que ahora cuando se agrega texto, guárdelo en una variable Vector (clase

variable), y en el método getView basado en la variable de posición, establezca el Texto (que puede

utiliza el método elementAt() del vector) del EditText correspondiente.

y no olvide agregar este EditText a la Vista inflada.

Este código te ayudará

 private class EfficientAdapter extends BaseAdapter { private LayoutInflater mInflater; private String[] attitude_names; public String[] attitude_values; private String name; public static HashMap myList=new HashMap(); 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 

Aquí he incluido un objeto HashMap que mantendrá a la vista lo que EditText contiene value.Y cuando se desplaza por la vista de lista, se volverá a representar llamando a su método getView.

En este código, cuando cargue listview por primera vez, todo el texto de edición estará sin texto. Una vez que ingrese un texto, se anotará en myList.So cuando vuelva a mostrar la lista, su texto se evitará.

Obtener paseo de la comprobación convertView == null y es otra statement. Va a obtener un peor rendimiento pero deshabilitará el reciclaje.

Mi adaptador amplía BaseAdapter y tuve una situación similar a la de bickster donde tuve una vista de lista que tenía vistas diferentes en ellos (una situación dinámica como la situación) y necesitaba persistir en los datos. Mi vista de lista no iba a ser demasiado grande, así que reciclar la vista no iba a ser un gran recurso en mi caso y, por lo tanto, un simple

if (convertView != null) return convertView;

al comienzo de getView fue suficiente para mí. No estoy seguro de qué tan eficiente es una solución, pero era lo que estaba buscando.

Edición importante: Esto está bien si y solo si tienes muy pocas filas (sin desplazamiento), de lo contrario, este truco es horrible. En su lugar, debe encargarse de los datos manualmente