Acceder

Ver la Versión Completa : [ SOLUCIONADO ] Editar atributo de campo dentro de un ArrayAdapter


Godlike
17/01/16, 20:49:17
Invoco a @kriogeN (http://www.htcmania.com/member.php?u=381391) y @mocelet (http://www.htcmania.com/member.php?u=510787) !! jaja

Buenas tardes compañeros,

hace un tiempo me ayudásteis mucho en el hilo:

http://www.htcmania.com/showthread.php?t=1052875


Me han pedido un pequeño cambio pero me cuesta tanto que llevo todo el día modificando cosas y no logro hacerlo funcionar. El problema que encuentro es que tengo un custom ArrayAdapter, gracias al cual creo una línea con varios campos cada vez que el usuario pulsa un botón para añadir "Conceptos".

Todo esto se basa en algo que me enseñásteis, y es en el modelo vista controlador, así que tengo un xml que es el que modela los campos que se muestran, luego el adapter en sí que controla la lógica, y un array donde se contienen realmente los datos.

Esta es la parte donde se maneja el comportamiento de uno de los campos, el que contiene el nombre del concepto:

final AutoCompleteTextView concepto = (AutoCompleteTextView) item.findViewById(R.id.conceptoId);
item.setTag(concepto);
concepto.setText(datos.get(pos).getNombre());
concepto.addTextChangedListener(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) {

}

override
public void afterTextChanged(Editable s) {
datos.get(pos).setNombre(concepto.getText().toStri ng());
if (datos.get(pos).getNombre().equals("")) {
if (datos.size() > 1) {
datos.remove(pos);
notifyDataSetChanged();
}
}
}
});
No tengo problemas en editar el adapter para manejar los datos como quiera, de hecho tengo un AutoCompleteTextView en uno de los campos y al seleccionar un item de la lista autocompleto otros campos recuperando datos de una base de datos. Sin embargo lo sé cómo actar sobre el campo en sí mismo.

Esta es la lógica que controla esto último

//Catch selected producto to fill details
concepto.setOnItemClickListener(new AdapterView.OnItemClickListener() {
override
//ATTENTION: This position variable can easily confuse with the main one. "pos" is the position from main getView, "position" is the relative to this function
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Getting the selected item to seek for other information of the producto
String producto = adapter.getItem(position);

//Log.d(TAG, "Estoy dentro del click!!");

Cursor cursorProducto = db.getFromProducto(producto);

if (cursorProducto != null && cursorProducto.moveToFirst()) {
datos.get(pos).setId(Integer.parseInt(cursorProduc to.getString(cursorProducto.getColumnIndex("id"))));
datos.get(pos).setCantidad(1);
datos.get(pos).setNombre(cursorProducto.getString( cursorProducto.getColumnIndex("nombre")));
datos.get(pos).setDescripcion(cursorProducto.getSt ring(cursorProducto.getColumnIndex("nombre"))); //Copying nombre to descripcion by default
datos.get(pos).setPrecio(Double.parseDouble(cursor Producto.getString(cursorProducto.getColumnIndex("precio_publico"))));
notifyDataSetChanged();
}

}
});

return(item);
}
Qué quiero conseguir: Tras seleccionar uno de los items, y por tanto autocompleto otros datos, bloquear ese campo para que ya no sea editable.

He tratado en la parte del programa que véis al final hacer:

concepto.setEnabled(false);Y funciona... pero me bloquea TODOS los campos de concepto, y no sé cómo aplicarlo sólamente a la línea que estoy editando y no a todos, es decir, poder diferenciar ese campo de ese mismo campo en otras "líneas", pero claro su "id" es el mismo porque en el XML sólo tengo la plantilla por así decirlo.

Agradezco de antemano cualquier ayuda :dios:

mocelet
18/01/16, 11:21:54
Cuando en Android buscas por identificador solo te devuelve una view. Y si buscas dentro de una fila (item.findView...) no te va a devolver views que estén en otras filas.

Así que el concepto.setEnabled(false) que mencionas se estará ejecutando en todas las filas porque la comprobación de la condición para que esté enabled o no será incorrecta.

Godlike
18/01/16, 11:54:39
Cuando en Android buscas por identificador solo te devuelve una view. Y si buscas dentro de una fila (item.findView...) no te va a devolver views que estén en otras filas.

Así que el concepto.setEnabled(false) que mencionas se estará ejecutando en todas las filas porque la comprobación de la condición para que esté enabled o no será incorrecta.

Buenas Mocelet, muchas gracias por responder.

El problema que me encuentro es exactamente el que mencionas, me he explicado quizá un poco mal pero has comprendido el problema perfecto.

¿De qué manera podría entonces acceder a ese campo en concreto? porque entiendo que se debe poder no? no sé cómo harán si no muchos juegos Android jaja

Gracias de nuevo

mocelet
19/01/16, 14:25:48
Me pierdo un poco entre conceptos, items y campos.

Ya que haces un notifyDataSetChanged() al autocompletar los datos a partir de la base de datos, se va a ejecutar otra vez el getView del adaptador. Es ahí donde tendrás que ver si llamar al setEnabled con true o con false. Esto es igual que cuando pones el texto, no buscas el campo, actualizas los datos y el campo refleja la información.

Si no tienes información suficiente en el array de datos para determinar si hay que habilitar o no la edición tendrás que añadir otro método del tipo setAutocompleted(true/false) para saber si esos datos los ha metido el usuario o se han generado automáticamente y no pueden editarse. Cuando sea por autogeneración haces un datos.get(pos).setAutocompleted(true) y cuando sea por el usuario lo mismo con false.

Así cuando tengas que pintar la celda en getView después de autocompletar lees el valor del boolean y ya sabes si hay que habilitar la edición o no.

Godlike
21/01/16, 14:54:09
Me pierdo un poco entre conceptos, items y campos.

Ya que haces un notifyDataSetChanged() al autocompletar los datos a partir de la base de datos, se va a ejecutar otra vez el getView del adaptador. Es ahí donde tendrás que ver si llamar al setEnabled con true o con false. Esto es igual que cuando pones el texto, no buscas el campo, actualizas los datos y el campo refleja la información.

Si no tienes información suficiente en el array de datos para determinar si hay que habilitar o no la edición tendrás que añadir otro método del tipo setAutocompleted(true/false) para saber si esos datos los ha metido el usuario o se han generado automáticamente y no pueden editarse. Cuando sea por autogeneración haces un datos.get(pos).setAutocompleted(true) y cuando sea por el usuario lo mismo con false.

Así cuando tengas que pintar la celda en getView después de autocompletar lees el valor del boolean y ya sabes si hay que habilitar la edición o no.

Hola mocelet,

muchas gracias por tu ayuda.

Siento el lío, no quiero inundarte con código porque demasiado que ayudas a tanta gente, pero por favor si lo prefieres para poder entender mejor lo que es cada cosa sólo dímelo.

De todas formas el tema es justo el que comentas, es decir, para mi el problema no es saber en qué momento lanzar la acción de establecer el campo como setEnabled(false), sino precisamente cómo actuar sobre ese campo.

Comentas que "Es ahí donde tendrás que ver si llamar al setEnabled con true o con false. Esto es igual que cuando pones el texto, no buscas el campo, actualizas los datos y el campo refleja la información."

Pero es exactamente ahí donde fallo, es decir, yo sé cómo modificar ese array "datos" porque lo tengo, y cuando leo ymodifico el valor de cualquier posición de este array de datos, la aplicación los muestra en la vista tras indicarle que se ha actualizado (notifyDataSetChanged()), pero si accedo a un dato de esta lista no puedo establecer setEnabled(false) porque no tiene sentido sobre un valor, sino sobre la vista en sí, pero no sé cómo modificar el campo, la vista (el getView) estando dentro del adapter.

Probablemente sea una chorrada pero es eso justo lo que me falla, es decir, supongamos que tengo suficiente información en los datos como para determinar el setEnabled a true o false (en principio me basta con el evento en que el usuario selecciona una opción de la lista del AutoComplete), pero no sé cómo ejecutar esta tarea:

"Así cuando tengas que pintar la celda en getView después de autocompletar lees el valor del boolean y ya sabes si hay que habilitar la edición o no"

Suponiendo que sé perfectamente si tengo que habilitar la edición o no, no sé cómo habilitarla sólo para ese campo. No sé si te refieres a que no es tipo un evento sino que cada vez que pinta tendrá que comprobar si ese campo es apto para ser establecido a setEnabled(true) o no, y no hacerlo como si fuera un evento como pretendo.

Si te refieres a esto último... comentas de hacer "datos.get(pos).setAutocompleted(true)", esto utilizará este método para cada valor de la lista y por tanto al dibujar y seguir la lógica de establecer a true o false el setEnabled para cada uno?, pensaba que al hacer esta sentencia se aplicaba a todos a la vez, pero tal vez simplemente se aplica a todos uno detrás de otro porque no hay filtro que determine qué hacer.


Muchas gracias por tanta ayuda,
un saludo!

mocelet
21/01/16, 18:24:02
No sé si te refieres a que no es tipo un evento sino que cada vez que pinta tendrá que comprobar si ese campo es apto para ser establecido a setEnabled(true) o no, y no hacerlo como si fuera un evento como pretendo.


Creo que ya hablamos de lo mismo. El evento desencadena la acción de autocompletado y desactiva una serie de campos, ¿no?

En vez de buscar la vista directamente y cambiarla, añade en algún sitio a los datos que ciertos atributos no pueden cambiarse porque han sido autogenerados. Así cuando la lista se refresque con el notifyDataSetChanged (y se llame al getView de cada fila) ya sabes para cada fila qué hay que tener activado o desactivado.

Si actualizas la vista "a pelo" pero no guardas nada en ningún sitio, con que el usuario haga scroll y se recicle una fila ya se ha liado porque pierdes el estado y aparecerán campos deshabilitados que no deberían y viceversa. El enabled a true o false de las cosas que puedan cambiar hazlo en el getView.

Godlike
22/01/16, 13:48:59
Creo que ya hablamos de lo mismo. El evento desencadena la acción de autocompletado y desactiva una serie de campos, ¿no?

En vez de buscar la vista directamente y cambiarla, añade en algún sitio a los datos que ciertos atributos no pueden cambiarse porque han sido autogenerados. Así cuando la lista se refresque con el notifyDataSetChanged (y se llame al getView de cada fila) ya sabes para cada fila qué hay que tener activado o desactivado.

Si actualizas la vista "a pelo" pero no guardas nada en ningún sitio, con que el usuario haga scroll y se recicle una fila ya se ha liado porque pierdes el estado y aparecerán campos deshabilitados que no deberían y viceversa. El enabled a true o false de las cosas que puedan cambiar hazlo en el getView.


Ahora si que entiendo a lo que te refieres!

Me he puesto a ello, te comento los cambios:

Al objecto "Concepto" le he añadido un par método como el que comentabas

//Others
public boolean getAutocompleted (){
return this.autoGenerated;
}
public void setAutocompleted (boolean estado){
this.autoGenerated = estado;
} Luego en el adapter lo que tengo es

private final ArrayList <Concepto> datos; De forma que una vez clica el usuario sobre un elemento del AutoCompleteTextView...

//Catch selected producto to fill details
concepto.setOnItemClickListener(new AdapterView.OnItemClickListener() {
override
//ATTENTION: This position variable can easily confuse with the main one. "pos" is the position from main getView, "position" is the relative to this function
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Getting the selected item to seek for other information of the producto
String producto = adapter.getItem(position);

//Log.d(TAG, "Estoy dentro del click!!");

Cursor cursorProducto = db.getFromProducto(producto);

if (cursorProducto != null && cursorProducto.moveToFirst()) {
datos.get(pos).setId(Integer.parseInt(cursorProduc to.getString(cursorProducto.getColumnIndex("id"))));
datos.get(pos).setCantidad(1);
datos.get(pos).setNombre(cursorProducto.getString( cursorProducto.getColumnIndex("nombre")));
datos.get(pos).setDescripcion(cursorProducto.getSt ring(cursorProducto.getColumnIndex("nombre"))); //Copying nombre to descripcion by default
datos.get(pos).setPrecio(Double.parseDouble(cursor Producto.getString(cursorProducto.getColumnIndex("precio_publico"))));
datos.get(pos).setAutocompleted(true);
notifyDataSetChanged();
}

}
});



Donde se ve que hago datos.get(pos).setAutocompleted(true);

La declaración del getView es esta:

public View getView(final int position, View convertView, ViewGroup parent){ Bueno pues aunque a continuación, o fuera del setOnItemClickListener (pero aún dentro del getView) haga:

View row = convertView;
if (datos.get(pos).getAutocompleted)
row.setEnabled(false);


No sucede nada, no crashea pero no hace nada de lo que debería hacer... algo se me escapa, ¿podrías echarme una mano por favor? Te lo agradezco muchísimo.

Un saludo!

mocelet
22/01/16, 14:01:51
El enabled en todo caso tendrás que hacerlo a cada uno de los cuadros de texto que quieras deshabilitar, no a la convertview (row) que sólo es un grupo de vistas.

Y el estado lo tienes que actualizar siempre, tanto para true como para false. Si no se quedará un valor antiguo al reciclar la fila.

Godlike
22/01/16, 14:15:52
El enabled en todo caso tendrás que hacerlo a cada uno de los cuadros de texto que quieras deshabilitar, no a la convertview (row) que sólo es un grupo de vistas.

Perdona mocelet, pero es justo eso lo que no sé cómo hacer, ¿podrías darme un ejemplo de código para que vea cómo podría acceder sólo a la vista y campo de texto de la "fila" en que me encuentro?

Y el estado lo tienes que actualizar siempre, tanto para true como para false. Si no se quedará un valor antiguo al reciclar la fila.

Lo que hago en la clase, cuando instancio el objeto de Concepto, es darle por defecto el valor "false" al boolean autocompleted. Por tanto cuando sé que ha sido autocompletado le asigno el valor "true" y actualizo con el notify. Cuando dices que actualice cuando está como false, te refieres a que lo establezca como "false" después de cada introduzcción de texto antes de actualizar si no ha sido seleccionado por el complete? ¿por qué cambiaría?


Mil gracias de nuevo

Godlike
22/01/16, 14:23:03
Funciona!!!!

Creo que esto resume lo que me decías que hiciera:


if (datos.get(pos).getAutocompleted())
concepto.setEnabled(false);
else
concepto.setEnabled(true);

notifyDataSetChanged();

donde concepto es
final AutoCompleteTextView concepto = (AutoCompleteTextView) item.findViewById(R.id.conceptoId);




Qué alegría!!! muchísimas gracias, tu ayuda es inestimable :dios:

Dexafree
22/01/16, 19:35:39
Solucionado entonces?

Si es asi puedes marcarlo como solucionado :ok:

Godlike
24/01/16, 16:36:28
Solucionado entonces?

Si es asi puedes marcarlo como solucionado :ok:

Hecho! ;)