Pregunta

Resumen: se trata de añadir dinámicamente filas de encabezado a un ListView a través de un adaptador de envoltorio personalizado. ListView está teniendo problemas para mantener la posición de desplazamiento en sincronía. proyecto de demostración ejecutable proporcionado.

Me gustaría añadir dinámicamente elementos a una lista basada en los valores de una CursorAdapter, varias posiciones de cara a lo que el usuario está viendo actualmente. Para hacer esto, tengo un adaptador que envuelve el CursorAdapter y mantiene el nuevo contenido indexado en un SparseArray. Las necesidades ListView que se actualizan cuando se agregan elementos al adaptador de costumbre, pero he conocido a un montón de trampas que intentan conseguir que al trabajo y les gustaría algún consejo.

El proyecto de demostración se puede descargar aquí: DynamicSectionedList.zip

En la demo, los títulos se añaden dinámicamente mirando hacia adelante 10 lugares para encontrar la posición correcta, donde los elementos de la lista cambia a la siguiente letra. Cada implementación de notifyDataSetChanged tiene problemas como se describe:

Demostración 1 Esta demostración muestra la importancia de notifyDataSetChanged (). Al hacer clic sobre cualquier cosa, la aplicación se bloquee. Esto es debido a algunas comprobaciones cordura en ListView ... mItemCount != adapter.getItemCount(). Moral es, tenemos que notificar la lista de datos que ha cambiado.

Demo 2 El siguiente paso natural es notificar al ListView de cambios cuando se produzcan cambios. Por desgracia, al hacerlo, mientras que el ListView se desplaza firmemente rompe toda la interacción táctil hasta que la aplicación cambia de modo táctil. Tendrá que "desplazamiento Fling" lo suficiente como para generar nuevas líneas con el fin de cuenta de esto. Al tocar la pantalla no hará que el desplazamiento de la parada, y una vez detenido ninguno de los elementos de la lista se podrá hacer clic. Esto se debe a algún código if (!mDataChanged) { /* do very important stuff */ } en AbsListView.onTouchEvent ().

Demostración 3 Para solucionar este problema, Demostración 3 introduce una bandera pendingChanges y las ganancias adaptador personalizado un notifyDataSetChangedIfNeeded () que puede ser llamado por el ListView una vez que ha entrado en un estado "seguro" para los cambios. El primer punto en el que deben ser notificados los cambios está en ListView.layoutChildren (), por lo que hizo caso omiso de ese método para notificar a la primera de cambios si es necesario, a continuación, llamar a través. Fling pasado al menos un título a continuación, en un elemento de la lista.

Esto no funciona bastante bien, aunque no estoy totalmente seguro de por qué. Al tocar o seleccionar un elemento con el teclado / bola de seguimiento hace que la lista para actualizar adecuadamente sin la sincronización de la posición de edad. Se desplaza a la parte superior de la lista que no es aceptable.

Demostración 4 El problema de desplazamiento en la demostración 3 puede ser conquistado, al menos en el modo táctil. Mediante la adición de una llamada a notifyDataSetChangedIfNeeded () en tocar tierra, el cambio de datos pasa a tener lugar en un momento de tal manera que toda la interacción táctil funciona como se esperaba y la posición de la lista se sincroniza correctamente.

Sin embargo, no puedo encontrar un análogo de que cuando el dispositivo no está en modo táctil, por no mencionar el hecho de que sin duda parece un truco. La lista casi siempre se desplaza de nuevo a la parte superior, no puedo averiguar lo que hace que se mantenga en ocasiones la posición correcta.

Dado que Android está luchando conmigo en cada paso del camino, siento que no debería haber un mejor enfoque. Por favor, probar la demo, si las correcciones se pueden aplicar para conseguir que funcione, que sería grande!

Muchas gracias a cualquiera que pueda ver en esto, es de esperar si podemos obtener el código trabajando será útil para otros tratando de lograr lo mismo para la optimización de las listas con los títulos.

¿Fue útil?

Solución

El principal problema con el enfoque presentado anteriormente era que el conjunto de datos se va a cambiar directamente desde dentro de código ejecutado por las superclases. Poblando las partidas de los getView () yo estaba cambiando los datos en lo que podría ser el medio de una operación o de un estado "inseguro" en las superclases. Esta es la razón por toda la interacción táctil se rompió cuando onNotifyDataSetChanged fue llamado durante un pergamino aventura. Los datos necesita ser añadido de una fuente externa, no desde dentro de los métodos de adaptador.

Esto se puede hacer mediante el uso de un manejador o AsyncTask añadir los títulos para el adaptador y llamar a su notifyDataSetChanged. Estos se ejecutan en un hilo de interfaz de usuario y no interferirán con el estado de la superclase. Gracias al ejemplo de EndlessAdapter CommonsWare para introducir el concepto de un AsyncTask para agregar datos a una lista.

El onTouchEvent () y layoutChildren () hacks ya no eran necesarios después de hacer que el cambio.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top