Programación y Desarrollo para Android Subforo exclusivo para temas de programación de software para PDAs y desarrollo de aplicaciones, interfaces, etc bajo Android

Respuesta
 
Herramientas
  #1  
Viejo 10/08/15, 16:40:35
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
Eliminar fila añadida mediante addView - Que no atino!!!

Buenas a todos,

Tengo un LinearLayout donde, con programación, añado "filas" al pulsar un botón. En realidad lo que hago es crear los elementos que quiero (una imagen, EditText...) y "unirlos" en una fila (un LinearLayout).

Luego añado ese LinearLayout al original y así consigo que se vayan añadiendo unas debajo de otras:

[php]public void addConcepto (View view) {
lineNumber++;
//Instance LinearLayout that is about to store each new Concepto line
LinearLayout li = (LinearLayout) findViewById(R.id.listConceptos);

//Creating new LinearLayout where I create new elements.
//This is what I am going actually to add to the first LinearLayout
LinearLayout horizontal = new LinearLayout(this);

//Building up the line by adding elements to the new LinearLayout
ImageButton et1 = new ImageButton(this);
EditText et2 = new EditText(this);
EditText et3 = new EditText(this);
EditText et4 = new EditText(this);

et1.setBackgroundColor(0);
et1.setImageResource(R.drawable.minus_icon2);
et1.setOnClickListener(new View.OnClickListener() { //Adding onClickListener to remove lines
public void onClick(View v) {
removeConcepto(lineNumber);
}
});
//ImageView et4 = new ImageView(this);

et2.setHint("Concepto");
et3.setHint("IVA");
et4.setHint("Precio");

et2.setWidth(150);
et3.setWidth(150);
et4.setWidth(150);
//et4.setWidth(150);

horizontal.addView(et1);
horizontal.addView(et2);
horizontal.addView(et3);
horizontal.addView(et4);

li.addView(horizontal);

//Globals.listaConceptos.add();
//et1.setTag(lineNumber);
}[/php]Pues bien, como veréis por los trozos que tengo comentados, estoy tratando de añadir una imagen al comienzo de cada fila, que es un signo de menos, y así cuando pulse quiero que esa línea se elimine.

Tengo esta función:

[php]public void removeConcepto (int line) {
LinearLayout li = (LinearLayout) findViewById(R.id.listConceptos);

//int pos = (Integer) view.getTag(1);
//li.removeViewAt(li.getChildCount());
li.removeViewAt(line);
}[/php]Que si pongo una línea fija, por ejemplo la "1", me la elimina. Pero no soy capaz de relacionar el número de fila con la fila real.

Mi intención era la que veis, un contador lineNumber que voy incrementando, y cuando creo la imagen de restar le asigno ese número al llamar a removeConcepto, pero me da fallos como si llamara a un objeto que no existe. Además de esta manera si creo tres filas, y borro la segunda. La que era la tercera seguirá teniendo el número "3" en su botón de borrar, cuando habrá pasado a ser el "2". No puede ser tan complicado!!.

Además de esto, como programador web que soy, me chirría que cada campo EditText no tenga un ID o nombre único, porque cuando el usuario acabe de añadir todas las filas (conceptos o productos en la aplicación) tendré que guardarlos todos en una base de datos... ¿cómo acceder a toda la información si no puedo diferenciar los campos?.

En PHP los campos tendrían en su nombre un ID dinámico, pero en Java aparte de no poderse hacer tal cual, es que no creo que sea tan "chapucero".

Por favor, cualquier ayuda será bienvenida.

Un saludo!

Última edición por Godlike Día 31/10/15 a las 17:58:35.
Responder Con Cita


  #2  
Viejo 10/08/15, 17:19:03
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

Lo suyo es que uses los patrones de diseño de Android y en concreto el patrón MVC (Modelo - Vista - Controlador) que es muy habitual en programación móvil y también en diversos frameworks web.

Para las listas tienes los ListView que precisamente ayudan a gestionar la presentación de listas de elementos (creas un layout a modo de plantilla de una fila y ya se encarga la implementación de poblar la lista a partir del modelo de datos, reutilizando vistas si se hace scroll para mejorar el rendimiento).

Los datos (el modelo) se almacenan en alguna estructura de datos (en memoria, base de datos, etc.) y se proporcionan a la interfaz de usuario (la vista) a través de los denominados adaptadores, y esos sí tienen constancia de la posición que ocupa un elemento en la lista para que cuando definas el listener del botón se borre lo que tiene que borrarse en el modelo y desaparezca la fila que tiene que desaparecer de la vista.

Esa es la forma de hacerlo en Android, aun así, si por lo que sea necesitas especificar algún identificador a un elemento, tienes los métodos setTag, getTag y findViewWithTag de las vistas que te permiten ponerle el nombre que quieras y buscarlo.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
  #3  
Viejo 10/08/15, 18:35:49
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
Muchísimas gracias compañero.

Tengo una actividad como mencionas, el problema es que lo hice sabiendo tan poco que no he tratado de repetirlo en estas listas que consideraba mucho más sencilla. La otra que tengo es mostrar en lista todos los elementos de una base de datos, y utilizo adaptadores como comentas.

Voy a darle una vuelta y ojalá no tenga que volver a preguntar

Gracias de nuevo!!
Responder Con Cita
  #4  
Viejo 14/08/15, 17:27:43
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
Lo suyo es que uses los patrones de diseño de Android y en concreto el patrón MVC (Modelo - Vista - Controlador) que es muy habitual en programación móvil y también en diversos frameworks web.

Para las listas tienes los ListView que precisamente ayudan a gestionar la presentación de listas de elementos (creas un layout a modo de plantilla de una fila y ya se encarga la implementación de poblar la lista a partir del modelo de datos, reutilizando vistas si se hace scroll para mejorar el rendimiento).

Los datos (el modelo) se almacenan en alguna estructura de datos (en memoria, base de datos, etc.) y se proporcionan a la interfaz de usuario (la vista) a través de los denominados adaptadores, y esos sí tienen constancia de la posición que ocupa un elemento en la lista para que cuando definas el listener del botón se borre lo que tiene que borrarse en el modelo y desaparezca la fila que tiene que desaparecer de la vista.

Esa es la forma de hacerlo en Android, aun así, si por lo que sea necesitas especificar algún identificador a un elemento, tienes los métodos setTag, getTag y findViewWithTag de las vistas que te permiten ponerle el nombre que quieras y buscarlo.

Buenas!

Tengo este fragmento de código que utilizo para listar el contenido de una tabla en base de datos:

[PHP]final Cursor cursor = db.getAllRowsPartes();
final String[] fromFieldNames = new String[]{MySQLiteHelper.KEY_PARTES_ID, MySQLiteHelper.KEY_PARTES_ID_CLIENTE, MySQLiteHelper.KEY_PARTES_HORA_INICIO, MySQLiteHelper.KEY_PARTES_HORA_FIN, MySQLiteHelper.KEY_PARTES_TECNICO, MySQLiteHelper.KEY_PARTES_NOTA_PUBLICA, MySQLiteHelper.KEY_PARTES_NOTA_INTERNA, MySQLiteHelper.KEY_PARTES_PERSONA_CONTACTO, MySQLiteHelper.KEY_PARTES_DNI, MySQLiteHelper.KEY_PARTES_EMAIL, MySQLiteHelper.KEY_PARTES_FECHA};
final int[] toViewIDs = new int[]{R.id.itemId, R.id.itemIdCliente, R.id.itemHinicio, R.id.itemHfin, R.id.itemTecnico, R.id.itemNpublica, R.id.itemNinterna, R.id.itemPcontacto, R.id.itemDni, R.id.itemEmail, R.id.selectedItem};
final SimpleCursorAdapter myCursorAdapter;
myCursorAdapter = new SimpleCursorAdapter(getBaseContext(), R.layout.activity_list_db_each, cursor, fromFieldNames, toViewIDs, 0);
final ListView myList = (ListView) findViewById(R.id.listDBitems);

myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//ItemClicked item = parent.getItemAtPosition(position);

Cursor itemCursor = (Cursor) myCursorAdapter.getItem(position);
String email = itemCursor.getString(cursor.getColumnIndex(MySQLit eHelper.KEY_PARTES_EMAIL));

Intent intent = new Intent(getApplicationContext(), EditParte.class);
intent.putExtra("email", email);
startActivity(intent);
}
});

myList.setAdapter(myCursorAdapter);
[/PHP]

El problema es que no consigo adaptarlo, ya que lo que tengo ahora no son datos que vengan de algún sitio, sino simplemente quiero introducir líneas con 3 campos de texto donde el usuario escribirá, y luego pasar los datos de todos esos campos a otro activity que los almacenará en una base de datos.

¿Podrías echarme una mano?
Responder Con Cita
  #5  
Viejo 14/08/15, 19:45:50
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

En vez de una base de datos SQlite usa un ArrayList de objetos (un array de objetos de tipo Gasto p.ej. que tenga tres variables: concepto, iva y precio). Los datos están en esa estructura de datos (modelo), las filas del listview realmente no son más que una representación visual (vista) de esos datos.

En vez de un SimpleCursorAdapter usa un ArrayAdapter

En vez de modificar la listview directamente o de añadir o eliminar vistas por tu cuenta, modifica el array de datos donde almacenes los valores de cada fila. Cuando modifiques algo (cambiar un valor, borrar o añadir un Gasto) tienes que llamar al método notifyDataSetChanged() del adapter para que la vista, es decir, la lista, se actualice con los nuevos datos. En otras palabras, no añades o quitas filas a la lista, las añades o quitas del array y ya se encarga Android de crear las filas.

Para editar es igual, si quieres que un usuario modifique un campo de una fila concreta (por el ejemplo al añadir un nuevo gasto que por defecto estará todo a cero p.ej.), en el listener de esa fila gracias al parámetro position puedes llamar a adapter.getItem(position) y tendrás el objeto de tipo Gasto correspondiente para modificarlo.

La clave es pensar en que los datos realmente no están en la lista o en los campos, están en un array y la lista se genera a partir de los datos de ese array.

Ventajas: no te preocupas de las vistas, y los datos luego no hay que "leerlos de los campos" porque en cualquier momento el estado está guardado en un array.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!

Última edición por mocelet Día 14/08/15 a las 19:47:55.
Responder Con Cita
Gracias de parte de:
  #6  
Viejo 15/08/15, 14:20:07
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
En vez de una base de datos SQlite usa un ArrayList de objetos (un array de objetos de tipo Gasto p.ej. que tenga tres variables: concepto, iva y precio). Los datos están en esa estructura de datos (modelo), las filas del listview realmente no son más que una representación visual (vista) de esos datos.

En vez de un SimpleCursorAdapter usa un ArrayAdapter

En vez de modificar la listview directamente o de añadir o eliminar vistas por tu cuenta, modifica el array de datos donde almacenes los valores de cada fila. Cuando modifiques algo (cambiar un valor, borrar o añadir un Gasto) tienes que llamar al método notifyDataSetChanged() del adapter para que la vista, es decir, la lista, se actualice con los nuevos datos. En otras palabras, no añades o quitas filas a la lista, las añades o quitas del array y ya se encarga Android de crear las filas.

Para editar es igual, si quieres que un usuario modifique un campo de una fila concreta (por el ejemplo al añadir un nuevo gasto que por defecto estará todo a cero p.ej.), en el listener de esa fila gracias al parámetro position puedes llamar a adapter.getItem(position) y tendrás el objeto de tipo Gasto correspondiente para modificarlo.

La clave es pensar en que los datos realmente no están en la lista o en los campos, están en un array y la lista se genera a partir de los datos de ese array.

Ventajas: no te preocupas de las vistas, y los datos luego no hay que "leerlos de los campos" porque en cualquier momento el estado está guardado en un array.

Buenas mocelet, antes de nada muchas gracias, sé el rollo que es ayudar a alguien con poca idea en estos temas, y más a través de un foro.

La realidad es que estoy echando tiempo en esto y solo con tu ayuda avanzo, me gustaría mostrarte lo que estoy intentando, algo se me escapa.

Para tratar de aplicar todo lo que me comentas tengo por un lado una clase Producto:

Código:
public class Producto {
    private int id;
    private String ref;
    private String nombre;
    private int iva;
    private int precio_publico;
    private String n_serie;

    public Producto (String ref, String nombre, int iva, int precio_publico, String n_serie){
        super();
        this.ref = ref;
        this.nombre = nombre;
        this.iva = iva;
        this.precio_publico = precio_publico;
        this.n_serie = n_serie;
}

    public Producto (){
        super();
        this.ref = null;
        this.nombre = null;
        this.iva = 0;
        this.precio_publico = 0;
        this.n_serie = null;
}

    //Getters
public int getId() { return this.id; }
    public String getRef (){
        return this.ref;
}
    public String getNombre(){
        return this.nombre;
}
    public int getIva(){
        return this.iva;
}
    public int getPrecio_publico(){
        return this.precio_publico;
}
    public String getN_serie(){
        return this.n_serie;
}

    //Setters
public void setId (int id) { this.id = id; }
    public void setRef (String ref){
        this.ref = ref;
}
    public void setNombre(String nombre){
        this.nombre = nombre;
}
    public void setIva(int iva){
        this.iva = iva;
}
    public void setPrecio_publico(int precio_publico){
        this.precio_publico = precio_publico;
}
    public void setN_serie(String n_serie){
        this.n_serie = n_serie;
}
}
Por otro lado, he creado un ArrayList en la Activity donde quiero hacer todo lo que te consulto:

Código:
ArrayList <Producto> Conceptos = new ArrayList<Producto>();
En el XML principal tengo el ListView donde quiero que vayan apareciendo las líneas al pulsar el botón:

Código:
<ListView
android:id="@+id/listConceptos"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</ListView>


He creado un XML a modo de plantilla para cada línea:

Código:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:descendantFocusability="blocksDescendants"
android:textIsSelectable="false" >

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.conde.adan.partesedreams.ParteTecnico"
android:orientation="vertical" >

        <LinearLayout
android:layout_width="wrap_content"
android:layout_height="150dp"
android:layout_marginLeft="10dp"
android:orientation="horizontal"
android:paddingTop="10dp" >

            <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="horizontal" >

                <ImageButton
android:id="@+id/delId"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/minus_icon2"
/>

                <EditText
android:id="@+id/conceptoId"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:paddingTop="20dp"
android:paddingLeft="5dp"
android:hint="Concepto"
android:textSize="20dp"/>

                <EditText
android:id="@+id/ivaId"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:paddingTop="20dp"
android:paddingLeft="5dp"
android:hint="IVA"
android:textSize="20dp"/>

                <EditText
android:id="@+id/precioId"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:paddingTop="20dp"
android:paddingLeft="5dp"
android:hint="Precio"
android:textSize="20dp"/>

            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
</ScrollView>
Y en la función de addConcepto trato de crear la vinculación:

Código:
final ArrayAdapter <Producto> myArrayAdapter = new ArrayAdapter <Producto> (this, android.R.layout.simple_list_item_1, Conceptos);
ListView listView = (ListView) findViewById(R.id.listConceptos);
listView.setAdapter(myArrayAdapter);

Pero tengo una sensación, y es que no quiero mostrar información de una base de datos o en un ArrayList como en este caso, sino añadir la plantilla XML cada vez que pulso el botón y, como comentas, poder controlar los datos y que Android se encargue de la visualización, pero todo esto que he hecho me lleva a pensar que estoy tratando de hacer lo contrario, mostrar información de algún sitio en la vista.

Siento abusar pero podrías darme otro empujón? básicamente quiero poder añadir ese XML cada vez que pulse un botón y capturar los datos escritos en cada campo al final del documento, imagino que esto podrá hacerse... lo que me dices me suena genial pero parece en tiempo real, no se me ocurre como hacer la verdad, no se si es almacenar los datos que escribe el usuario en el ArrayList y avisar al Adapter en cada momento.

Mil gracias de antemano!
Responder Con Cita
  #7  
Viejo 15/08/15, 15:34:29
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

 Cita: Originalmente Escrito por Godlike Ver Mensaje
Pero tengo una sensación, y es que no quiero mostrar información de una base de datos o en un ArrayList como en este caso, sino añadir la plantilla XML cada vez que pulso el botón y, como comentas, poder controlar los datos y que Android se encargue de la visualización, pero todo esto que he hecho me lleva a pensar que estoy tratando de hacer lo contrario, mostrar información de algún sitio en la vista.
Lo has entendido perfectamente, y esa es la base del patrón MVC (modelo-vista-controlador), tener separados los datos de la presentación y de la lógica. Y cuando cambias algo, lo cambias en el modelo de datos, no en la vista. La vista simplemente refleja los datos.

Ahora bien, puedes pensar que no tienes ningún dato porque quieres que el usuario los introduzca. Eso es correcto, pero necesitas un sitio donde guardar los datos introducidos, el ArrayList de Producto, que al principio estará vacío.

En vez de pensar en "añadir la plantilla XML cuando pulse el botón" para que el usuario escriba en una nueva fila, piensa en añadir un nuevo Producto al array. Inicialmente ese producto tendrá los atributos a cero o al valor por defecto que pongas, y gracias al adaptador y al listview se creará automáticamente una nueva fila a partir de la plantilla XML (que, por cierto, el ScrollView te sobra, una única fila no tiene scroll, y la listview ya lo lleva).

Esa nueva fila tendrá campos EditText con valores por defecto que el usuario tendrá que cambiar. En vez de esperar a que el usuario rellene todo, puedes ir guardando en el Producto asociado los valores según se van añadiendo gracias al listener de los EditText (addTextChangedListener) que te indican que se ha editado un campo, o a un botón de guardar que pongas en cada fila o como quieras.

Así siempre tienes el array actualizado con los datos del usuario, y si introduce algo incorrecto puedes indicarlo en la propia fila antes de guardarlo, cambiarle el color o cualquier indicador para el usuario.

Igual es matar moscas a cañonazos para introducir uno o dos productos... pero si un día añade muchos o si tienes casos como el de ahora elimino una fila, ahora añado otra, etc. no te dará ningún problema.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Gracias de parte de:
  #8  
Viejo 15/08/15, 19:58:39
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
Lo has entendido perfectamente, y esa es la base del patrón MVC (modelo-vista-controlador), tener separados los datos de la presentación y de la lógica. Y cuando cambias algo, lo cambias en el modelo de datos, no en la vista. La vista simplemente refleja los datos.

Ahora bien, puedes pensar que no tienes ningún dato porque quieres que el usuario los introduzca. Eso es correcto, pero necesitas un sitio donde guardar los datos introducidos, el ArrayList de Producto, que al principio estará vacío.

En vez de pensar en "añadir la plantilla XML cuando pulse el botón" para que el usuario escriba en una nueva fila, piensa en añadir un nuevo Producto al array. Inicialmente ese producto tendrá los atributos a cero o al valor por defecto que pongas, y gracias al adaptador y al listview se creará automáticamente una nueva fila a partir de la plantilla XML (que, por cierto, el ScrollView te sobra, una única fila no tiene scroll, y la listview ya lo lleva).

Esa nueva fila tendrá campos EditText con valores por defecto que el usuario tendrá que cambiar. En vez de esperar a que el usuario rellene todo, puedes ir guardando en el Producto asociado los valores según se van añadiendo gracias al listener de los EditText (addTextChangedListener) que te indican que se ha editado un campo, o a un botón de guardar que pongas en cada fila o como quieras.

Así siempre tienes el array actualizado con los datos del usuario, y si introduce algo incorrecto puedes indicarlo en la propia fila antes de guardarlo, cambiarle el color o cualquier indicador para el usuario.

Igual es matar moscas a cañonazos para introducir uno o dos productos... pero si un día añade muchos o si tienes casos como el de ahora elimino una fila, ahora añado otra, etc. no te dará ningún problema.

Gracias de nuevo, me parece genial hacerlo así, la intención de hacer esta aplicación es ayudar a una persona en su empresa, pero sobretodo aprender Android, y hacerlo bien ahora aunque sea para muy pocos productos me vendrá mejor que bien para cuando tenga que hacer algo más complejo, que seguro llegará.

Probablemente con lo que me has dicho debería ya ser capaz de hacerlo por mi mismo, pero salvo eliminar el ScrollView y entender bien lo que me dices, no soy capaz de aplicarlo en la práctica (esto es lo que más me está costando en Android).

Esto lo declaro al inicio del Activity:

Código:
ArrayList <Producto> Conceptos = new ArrayList<Producto>();
Y para mí debería también ir ahí:

Código:
ArrayAdapter <Producto> myArrayAdapter = new ArrayAdapter <Producto> (this, android.R.layout.simple_list_item_1, Conceptos);
Pero así la aplicación crashea, de forma que lo he dejado dentro de la función addConcepto (al que llamo al pulsar una imagen).

La duda principal que tengo, una vez me encuentro en addConcepto con esto:

Código:
ArrayAdapter <Producto> myArrayAdapter = new ArrayAdapter <Producto> (this, android.R.layout.simple_list_item_1, Conceptos);
ListView listView = (ListView) findViewById(R.id.listConceptos);
listView.setAdapter(myArrayAdapter);
Es que falta algo, no hay acción! y de hecho al pulsar el botón no pasa nada... es cierto que los productos no existen y de hecho están vacíos, voy a probar a crear uno cada vez que pulso añadir, pero aún así no lo tendré bindeado a esa línea, ¿no?.

¿Faltaría hacer una clase de ArrayAdapter para decirle todos los campos que tengo en Producto y cómo tratarlos? ¿O con lo que tengo ya basta con crear una instancia de Producto?.

La teoría creo que debería ser crear en efecto esa instancia de Producto, permitir al usuario añadir datos a la línea que aparecerá (no sé cómo Android sabrá que ese producto es del ArrayList) y con la función que me dices (no la conocía y me viene genial) ir almacenando los datos.

Luego, en caso de pulsar la imagen de borrar línea, elimino el Producto de esa posición del ArrayList... pero como te digo esto es lo que creo que hay que hacer, me falta algo en el código que no cuadra todo

EDIT:

He añadido estas líneas al principio, creando un Producto que añado al Array:

Código:
Producto myProducto = new Producto();
myProducto.setId(3);
myProducto.setIva(21);
myProducto.setN_serie("409KNG");
myProducto.setRef("315F");
myProducto.setNombre("PRODUCTO 1");
myProducto.setPrecio_publico(57);
Conceptos.add(myProducto);

ArrayAdapter <Producto> myArrayAdapter = new ArrayAdapter <Producto> (this, android.R.layout.simple_list_item_1, Conceptos);
ListView listView = (ListView) findViewById(R.id.listConceptos);
listView.setAdapter(myArrayAdapter);
Ahora cuando le doy al botón de añadir me añade una fila (al menos va por ahí la cosa!) pero es el nombre de mi app jaja... "com.miapellido.minombre.laempresa.Producto@52a7f6 e4"

Incluso si soluciono esto, pulsando más veces sobre el botón de añadir producto no hace nada, es como que estoy mostrando todos los datos contenidos en el Array pero necesitaría que me introdujera más, para poder escribir en los campos

Última edición por Godlike Día 15/08/15 a las 20:11:48.
Responder Con Cita
  #9  
Viejo 15/08/15, 20:32:00
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

Vas bien encaminado, en efecto falta un poco de "pegamento" para que todo funcione bien.

El adaptador tiene que saber crear las vistas de la listview a partir de la plantilla (el layout)

Échale un vistazo a este tutorial:
http://www.sgoliver.net/blog/interfa...-seleccion-ii

Aunque en el fondo es parecido a lo que tenías para sqlite.
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Gracias de parte de:
  #10  
Viejo 16/08/15, 02:01:24
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
Vas bien encaminado, en efecto falta un poco de "pegamento" para que todo funcione bien.

El adaptador tiene que saber crear las vistas de la listview a partir de la plantilla (el layout)

Échale un vistazo a este tutorial:
http://www.sgoliver.net/blog/interfa...-seleccion-ii

Aunque en el fondo es parecido a lo que tenías para sqlite.

Hola de nuevo,

he estado siguiendo la guía del link que me has pasado y me ha aclarado muchísimo, ahora tiene sentido, lo que faltaba, el "pegamento". Sin embargo estoy atascado en algo algo técnico...

Por un lado, aunque en el ejemplo utilizan Titulo[] foo = new titulo ...

Yo tengo ArrayList <Producto> foo = new ...

Entiendo que no tiene más importancia, lo que hago para que funcione así es que en la clase del Adapter customizado hago:

Código:
concepto.setText(datos.get(position).getNombre());
En lugar de datos[position].getNombre();

Esto creo que está bien.


Pero obtenía un error al pulsar el botón ya testeando el programa, me decía algo de ID y TextView... buscando por Internet (http://stackoverflow.com/questions/9...w-xml-problems)
encuentro que ArrayAdapter necesita un TextView a "pelo", o bien modificar su constructor... pero eso es justamente lo que estaba haciendo!:

Código:
public ConceptoAdapter (Context context, ArrayList<Producto> datos){
    super(context, R.layout.activity_parte_tecnico_each, R.id.TVid, datos);
}
Me he inventado un TextView en el XML, aunque no lo necesito, y he indicado su ID en la linea que ves, y así al pulsar el botón por fin se inserta... pero las letras que te comentaba que salían del nombre de mi aplicación ahora salen en ese TextView, y a continuación todos los EditText que si que necesito.

El problema es que no necesito ningún TextView, y por otro lado aunque pulse varias veces el botón no se insertan más líneas, a pesar de crear un Producto y añadirlo al ArrayList en cada pulsación. Pensaba que sería cosa de usar notifyDataSetChanged() pero no parece que sea eso:

Código:
public void addConcepto (View view) {
    Producto myProducto = new Producto();
conceptos.add(myProducto);

ConceptoAdapter myAdapter = new ConceptoAdapter (this, conceptos);
ListView listView = (ListView) findViewById(R.id.listConceptos);
listView.setAdapter(myAdapter);

myAdapter.notifyDataSetChanged();
A ver si pudieras echarme otro cable... si necesitas cualquier captura o código solo pídemelo

Esta es de lo último que me falta para terminar la app v0.1 jeje...

Saludos!
Responder Con Cita
  #11  
Viejo 16/08/15, 09:04:22
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

No me había fijado en el tema del TextView, siempre puedes hacer un apaño... que es crear un TextView invisible solo para que se quede contento. Está hecho para crear listas rápidamente, el texto raro que te pone es el toString() de Producto, que como no tiene ninguno es el identificador del objeto Java. Pero vamos, con este TextView de mentira lo resuelves rápido, ponlo en cualquier sitio de la fila que no ocupa espacio ni nada (o ponle el atributo de visibilidad gone al que ya tienes):

Código:
   <TextView
        android:id="@+id/fakeText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
En el addConcepto parece que además de añadir el nuevo producto y llamar al notifyDataSetChanged (es lo único que hay que hacer) también vuelves a crear el adaptador e inicializar la lista. El adaptador tienes que crearlo solo una vez y asociarlo a la lista solo una vez, por ejemplo en el onCreate. Si no difícilmente podrán mantener el estado de la lista.

Así que esas tres líneas de crear adapter, buscar listview y asociar adapter ponlas en onCreate, y en el addConcepto solo añade el producto al array y llama al notifyDataSetChanged. Con eso debería funcionar, o al menos estar más cerca de que funcione
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Gracias de parte de:
  #12  
Viejo 16/08/15, 20:38:16
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
Gracias!

Ya aparecen bien! me quedan dos cosas, me siento taaaan torpe con Android...

Mira, tengo esto declarado al inicio del Activity:

Código:
ArrayList <Producto> conceptos = new ArrayList<Producto>();
ConceptoAdapter myAdapter;
ListView listView;
En el OnCreate (entre otras muchas cosas):

Código:
myAdapter = new ConceptoAdapter (this, conceptos);
listView = (ListView) findViewById(R.id.listConceptos);
listView.setAdapter(myAdapter);
Y por último la función de addConcepto:

Código:
public void addConcepto (View view) {
    Producto myProducto = new Producto();
conceptos.add(myProducto);

myAdapter.notifyDataSetChanged();
}
El problema hasta aquí: Siguen sin añadirse más de una fila, por más que pulse el botón. Tampoco tengo claro cómo coger luego todos los datos, pero imagino que es cuestión de usar la función que me comentaste y almacenar los valores conforme se modifican en la posición que toque, o bien hacerlo al final del todo con un botón recorriendo el ArrayList.

Pero el otro problema está relacionado con ese, tengo otra función:

Código:
public void removeConcepto (View view) {
}
Y no sé cómo acceder a la position correcta de myAdapter. Este es mi adaptador customizado completo:

Código:
public class ConceptoAdapter extends ArrayAdapter {
    public ConceptoAdapter (Context context, ArrayList<Producto> datos){
        super(context, R.layout.activity_parte_tecnico_each, R.id.fakeText, datos);
}

    public View getView(int position, View convertView, ViewGroup parent, ArrayList <Producto> datos){
        LayoutInflater inflater = LayoutInflater.from(getContext());
View item = inflater.inflate(R.layout.activity_parte_tecnico_each, null);

EditText concepto = (EditText) item.findViewById(R.id.conceptoId);
concepto.setText(datos.get(position).getNombre());

EditText iva = (EditText) item.findViewById(R.id.ivaId);
iva.setText(datos.get(position).getIva());

EditText precio = (EditText) item.findViewById(R.id.precioId);
precio.setText(datos.get(position).getPrecio_publico());

        return(item);
}

}
He tratado de meterle algo igual al EditText pero de la imagen de delete, que por cierto es:

Código:
<ImageButton
android:id="@+id/delId"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/minus_icon2"
/>
Pero no sé cómo sacar la posición, de hecho en el Adapter es una variable pasada por referencia, y yo no sé ni dónde se la paso intuyo que de la vista, de forma automática, pero no se si debería hacer un getPosition o qué, no sé cómo sacarla!

Ojalá termine esto antes de que te desesperes conmigo
Responder Con Cita
  #13  
Viejo 16/08/15, 21:07:22
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
Añado rápidamente que si que se añaden más ahora! aunque con scroll y no muy juntas unas de otras, modificaré el XML

Me queda saber básicamente la position para diferenciarlas y guardar la info, que creo que será poner el listener y sabiendo la position almacenar el valor del campo en el ArrayList (es la misma position o puedo saber que estoy en ESTE campo?). Además así podré eliminar filas
Responder Con Cita
  #14  
Viejo 16/08/15, 21:18:52
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

¿Seguro que se muestra alguna fila? El método getView de ArrayAdapter que tienes que sobreescribir tiene tres parámetros, no cuatro, así que borra el último:

[PHP] @override
public View getView(int position, View convertView, ViewGroup parent) {[/PHP]

Poner el @override es interesante porque así Android Studio te avisa de si de verdad estás sobreescribiendo el método o no. Puedes comprobarlo poniendo el @override antes de cambiar los parámetros.

Sobre borrar, una opción es prescindir del removeConcepto y definir el listener dentro del adaptador al crear la vista de esa fila, es decir, dentro del getView. Algo así:

[PHP]
View removeButton = item.findViewById(R.id.button);
final int pos = position;
removeButton.setOnClickListener(new View.OnClickListener() {
@override
public void onClick(View v) {
conceptos.remove(pos);
notifyDataSetChanged();
}
});[/PHP]

Otra opción es usar el setTag y el getTag que te comentaba en el primer post, de modo que en la vista guardas la posición para poder recuperarla en el removeConcepto. Entonces en vez del onClickListener lo que haces es un removeButton.setTag(position) y en el método removeConcepto haces lo mismo del onClick pero con pos = view.getTag();

Elige la que más rabia te dé

P.D: Ignoro cómo poner la arroba en el foro para que salga bien en el código y no lo confunda con una mención a un usuario
P.D.2: He borrado un "myAdapter." que sobraba, ya estás en el adaptador
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!

Última edición por mocelet Día 16/08/15 a las 21:28:42.
Responder Con Cita
  #15  
Viejo 17/08/15, 19:42:53
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
¿Seguro que se muestra alguna fila? El método getView de ArrayAdapter que tienes que sobreescribir tiene tres parámetros, no cuatro, así que borra el último:

[php] @override
public View getView(int position, View convertView, ViewGroup parent) {[/php]Poner el @override es interesante porque así Android Studio te avisa de si de verdad estás sobreescribiendo el método o no. Puedes comprobarlo poniendo el @override antes de cambiar los parámetros.

Sobre borrar, una opción es prescindir del removeConcepto y definir el listener dentro del adaptador al crear la vista de esa fila, es decir, dentro del getView. Algo así:

[php]
View removeButton = item.findViewById(R.id.button);
final int pos = position;
removeButton.setOnClickListener(new View.OnClickListener() {
@override
public void onClick(View v) {
conceptos.remove(pos);
notifyDataSetChanged();
}
});[/php]Otra opción es usar el setTag y el getTag que te comentaba en el primer post, de modo que en la vista guardas la posición para poder recuperarla en el removeConcepto. Entonces en vez del onClickListener lo que haces es un removeButton.setTag(position) y en el método removeConcepto haces lo mismo del onClick pero con pos = view.getTag();

Elige la que más rabia te dé

P.D: Ignoro cómo poner la arroba en el foro para que salga bien en el código y no lo confunda con una mención a un usuario
P.D.2: He borrado un "myAdapter." que sobraba, ya estás en el adaptador

Hola de nuevo!!

Antes de nada, mil gracias. No sé si lo creerás pero esto es como un cursillo intenso para mi, he comprendido perfectamente el patrón MVC e incluso he estado viendo videos de cómo funciona en otras plataformas, como la web, donde nunca lo he utilizado.

Mira, he colocado lo que me dices (tiene todo el sentido hacerlo desde dentro de la propia clase, donde la vista tiene la posición!! desconozco de dónde la saca Android pero supongo que ya lo aprenderé más adelante, de momento con que funcione...):

[PHP @override
public View getView(final int position, View convertView, ViewGroup parent, ArrayList <Producto> datos){
LayoutInflater inflater = LayoutInflater.from(getContext());
View item = inflater.inflate(R.layout.activity_parte_tecnico_e ach, null);

View removeButton = item.findViewById(R.id.delId);
final int pos = position;
removeButton.setOnClickListener(new View.OnClickListener() {
@override
public void onClick(View v) {
datos.remove(pos);
notifyDataSetChanged();
}
});

EditText concepto = (EditText) item.findViewById(R.id.conceptoId);
concepto.setText(datos.get(position).getNombre());

EditText iva = (EditText) item.findViewById(R.id.ivaId);
iva.setText(datos.get(position).getIva());

EditText precio = (EditText) item.findViewById(R.id.precioId);
precio.setText(datos.get(position).getPrecio_publi co());

return(item);
}[/PHP]

(Te copio, que con código PHP parece que queda mejor visualmente)

Como curiosidad, esta línea

[PHP]removeButton.setOnClickListener(new View.OnClickListener() {[/PHP]

No me lo reconocía así, de forma que probé simplemente con "new OnClickListener() ..." y él solo añadió lo de View.OnClickListener luego, son cosas que aún no entiendo

Ahora, sobre lo que comentas... efectivamente me tomé la libertad de añadir ese parámetro, y efectivamente también, si comento la línea de

[PHP]datos.remove(pos);[/PHP]

El @override de arriba del getView indica que no estoy sobreescribiendo el método, como bien me decías. El problema es que la guía que seguí del link que me pasaste tienen esta clase dentro del propio Activity, y yo lo tengo aparte, así que la variable "datos" no está reconocida. Desconozco cómo hacer para que esta clase sepa a qué me refiero, así como cuando me dices que ponga:

[PHP] conceptos.remove(pos);[/PHP]

he puesto "datos.remove(pos);" ya que "conceptos" no lo tengo en esta clase tampoco. Si no la comento el Override no "se queja", pero en la línea "datos.remove(pos);" dice "Variable 'datos' is accessed from within inner class, needs to be declared final.

Aquí falta algo y creo que será la clave de todo, porque solucionaría el Override del getView, y tendría la variable "datos" reconocida, que actualmente mi programa, si elimino "ArraList <Producto> datos" de los parámetros de getView no reconocería esa variable

Gracias de nuevo
Responder Con Cita
  #16  
Viejo 17/08/15, 21:12:38
Array

[xs_avatar]
kriogeN kriogeN no está en línea
Colaborador/a
· Votos compra/venta: (1)
 
Fecha de registro: oct 2010
Localización: Murcia
Mensajes: 4,637
Modelo de smartphone: Samsung Galaxy S7 Edge SM-G935F
Tu operador: Vodafone
El problema está en que getView debe ser:
@override
public View getView(final int position, View convertView, ViewGroup parent)

Si añades el parámetro "datos"es una función distinta, y por eso se queja al añadirle el @override, porque te está diciendo "¿Qué quieres que sobreescriba si esto no existe en mi padre?

La forma correcta es pasar los datos en el constructor, o si los datos van a ser cambiantes, tener una función llamada "setDatos" a la que asignas los datos y haces el notifyDataSetChanged().

Es decir, algo así:

[PHP]

ArrayList <Producto> datos = null;

public void setDatos(ArrayList <Producto> datos) {
this.datos = datos;
this.notifyDataSetChanged();
}
[/PHP]

Añadiendo eso a la clase y dejando getView como te he indicado antes debería funcionarte bien.

Ahora ya lo único que tienes que hacer en la clase cliente es llamar a setDatos inmediatamente después del constructor del ArrayAdapter.
Responder Con Cita
Gracias de parte de:
  #17  
Viejo 17/08/15, 21:42:00
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

Poco que añadir a lo dicho por kriogeN.

Dado que usa un ArrayAdapter, la lista no va a cambiar porque el adaptador está ligado ya al array que se le pasa. Así que pasaría el array datos por el constructor y lo almacenaría como variable final.

Si no, puede que se le olvide llamar al setDatos o, peor, que lo llame más veces para cambiar el array y la lista esté ligada a un array pero él toque otro array distinto.

EDIT: Es decir:

Código:
public class ConceptoAdapter extends ArrayAdapter {
   private final ArrayList<Producto> datos;

   public ConceptoAdapter (Context context, ArrayList<Producto> datos){
        super(context, R.layout.activity_parte_tecnico_each, R.id.fakeText, datos);
        this.datos = datos;
}
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!

Última edición por mocelet Día 17/08/15 a las 21:50:50.
Responder Con Cita
Gracias de parte de:
  #18  
Viejo 17/08/15, 21:56:18
Array

[xs_avatar]
kriogeN kriogeN no está en línea
Colaborador/a
· Votos compra/venta: (1)
 
Fecha de registro: oct 2010
Localización: Murcia
Mensajes: 4,637
Modelo de smartphone: Samsung Galaxy S7 Edge SM-G935F
Tu operador: Vodafone
 Cita: Originalmente Escrito por mocelet Ver Mensaje
Poco que añadir a lo dicho por kriogeN.

Dado que usa un ArrayAdapter, la lista no va a cambiar porque el adaptador está ligado ya al array que se le pasa. Así que pasaría el array datos por el constructor y lo almacenaría como variable final.

Si no, puede que se le olvide llamar al setDatos o, peor, que lo llame más veces para cambiar el array y la lista esté ligada a un array pero él toque otro array distinto.

EDIT: Es decir:

Código:
public class ConceptoAdapter extends ArrayAdapter {
   private final ArrayList<Producto> datos;

   public ConceptoAdapter (Context context, ArrayList<Producto> datos){
        super(context, R.layout.activity_parte_tecnico_each, R.id.fakeText, datos);
        this.datos = datos;
}
Nunca he usado ArrayAdapter, siempre usaba BaseAdapter, y desde hace casi 1 año uso RecyclerView.Adapter. Así que no sabía que no se podían cambiar, pensaba que era como el BaseAdapter en ese sentido. Y si, lo mejor es hacerlo en el constructor. De hecho aunque tengas un setDatos y se trate de un BaseAdapter no está de más pasar siempre la "primera colección" en el constructor.

Última edición por kriogeN Día 17/08/15 a las 21:58:26.
Responder Con Cita
Gracias de parte de:
  #19  
Viejo 17/08/15, 22:06:23
Array

[xs_avatar]
Godlike Godlike no está en línea
Miembro del foro
 
Fecha de registro: jul 2015
Mensajes: 101
Modelo de smartphone: LG G5
Tu operador: Vodafone
Vaya lujo teneros dándome consejos... gracias a ambos, voy a tratar de sacar un rato hoy o mañana para probarlo y os cuento

GRACIAS!
Responder Con Cita


  #20  
Viejo 17/08/15, 22:20:30
Array

[xs_avatar]
mocelet mocelet no está en línea
Desarrollador
 
Fecha de registro: may 2011
Localización: Madrid
Mensajes: 2,202
Tu operador: -

 Cita: Originalmente Escrito por kriogeN Ver Mensaje
Nunca he usado ArrayAdapter, siempre usaba BaseAdapter, y desde hace casi 1 año uso RecyclerView.Adapter. Así que no sabía que no se podían cambiar, pensaba que era como el BaseAdapter en ese sentido. Y si, lo mejor es hacerlo en el constructor. De hecho aunque tengas un setDatos y se trate de un BaseAdapter no está de más pasar siempre la "primera colección" en el constructor.
Lo cierto es que yo tampoco Le recomendé el ArrayAdapter por su sencillez (solo tenía que implementar el getView, ¡o eso parecía en teoría!).

Después vino la "chapucilla" porque si no hay TextViews no le gusta. Luego la segunda chapucilla de tener que guardar la referencia de la lista porque el ArrayAdapter se la guarda para él pero luego no te expone métodos como poder borrar por posición. Sin embargo sí te permite añadir o consultar una posición.

Al final, salvo para aprender, compensa implementarse el adaptador desde cero a partir de la clase base, al menos así se está seguro de qué está haciendo exactamente.

 Cita: Originalmente Escrito por Godlike Ver Mensaje
Vaya lujo teneros dándome consejos... gracias a ambos, voy a tratar de sacar un rato hoy o mañana para probarlo y os cuento

GRACIAS!
Suerte ;)
__________________
El mejor Cuatro en Raya de Android (Hilo en HTCMania, Play Store) ¡Un millón de descargas!
Responder Con Cita
Gracias de parte de:
Respuesta

Estás aquí
Regresar   Portal | Indice > Todo sobre Android > Programación y Desarrollo para Android



Hora actual: 05:07:26 (GMT +2)



User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.

Contactar por correo / Contact by mail / 邮件联系 /