¿Cómo puedo crear una lista en la que, cuando llegue al final de la lista, se me notifique para que pueda cargar más elementos?
Lista interminable de Android
isaac waller
Josef Pfleger
Una solución es implementar un OnScrollListener
y hacer cambios (como agregar elementos, etc.) al ListAdapter
en un estado conveniente en su onScroll
método.
La siguiente ListActivity
muestra una lista de números enteros, comenzando con 40, agregando elementos cuando el usuario se desplaza hasta el final de la lista.
public class Test extends ListActivity implements OnScrollListener {
Aleph0 adapter = new Aleph0();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(adapter);
getListView().setOnScrollListener(this);
}
public void onScroll(AbsListView view,
int firstVisible, int visibleCount, int totalCount) {
boolean loadMore = /* maybe add a padding */
firstVisible + visibleCount >= totalCount;
if(loadMore) {
adapter.count += visibleCount; // or any other amount
adapter.notifyDataSetChanged();
}
}
public void onScrollStateChanged(AbsListView v, int s) { }
class Aleph0 extends BaseAdapter {
int count = 40; /* starting amount */
public int getCount() { return count; }
public Object getItem(int pos) { return pos; }
public long getItemId(int pos) { return pos; }
public View getView(int pos, View v, ViewGroup p) {
TextView view = new TextView(Test.this);
view.setText("entry " + pos);
return view;
}
}
}
Obviamente, debe usar subprocesos separados para acciones de ejecución prolongada (como cargar datos web) y es posible que desee indicar el progreso en el último elemento de la lista (como lo hacen las aplicaciones Market o Gmail).
-
eh, ¿no provocaría esto que aumentara el tamaño del adaptador si dejaras de desplazarte en el medio de la pantalla? solo debería cargar los siguientes 10 cuando llegue al final de la lista.
– Matías
5 de agosto de 2010 a las 10:13
-
Veo muchos ejemplos como este usando BaseAdapter. Quería mencionar que si está usando una base de datos, intente usar un SimpleCursorAdapter. Cuando necesite agregar a la lista, actualice su base de datos, obtenga un nuevo cursor y use SimpleCursorAdapter#changeCursor junto con notificarDataSetChanged. No se requieren subclases y funciona mejor que un BaseAdapter (nuevamente, solo si está usando una base de datos).
– soporte
20 de octubre de 2010 a las 18:51
-
Después de llamar a notificarDataSetChanged(), aparecerá en la parte superior de la lista, ¿cómo puedo evitarlo?
– dibujar
2 de septiembre de 2011 a las 12:57
-
Una nota: utilicé este enfoque, pero necesitaba agregar una verificación para cuando visibleCount es 0. Para cada lista, recibo una devolución de llamada a onScroll donde firstVisible, visibleCount y totalCount son todos 0, lo que técnicamente cumple con el condicional, pero no es cuando quiero cargar más.
– Eric Molino
5 de enero de 2012 a las 22:37
-
Otro problema con este código es que la condición
firstVisible + visibleCount >= totalCount
se cumple varias veces con múltiples llamadas al oyente. Si la función de cargar más es una solicitud web (lo más probable es que lo sea), agregue otra verificación para ver si la solicitud está en curso o no. Por otro lado, verifique si totalCount no es igual al recuento total anterior, porque no necesitamos múltiples solicitudes para la misma cantidad de elementos en la lista.– C–
24 de agosto de 2012 a las 20:14
saschoar
Solo quería contribuir con una solución que usé para mi aplicación.
También se basa en la OnScrollListener
interfaz, pero descubrí que tiene un rendimiento de desplazamiento mucho mejor en dispositivos de gama baja, ya que ninguno de los cálculos de conteo visible/total se lleva a cabo durante las operaciones de desplazamiento.
- Deja que
ListFragment
oListActivity
implementarOnScrollListener
-
Agregue los siguientes métodos a esa clase:
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //leave this empty } @Override public void onScrollStateChanged(AbsListView listView, int scrollState) { if (scrollState == SCROLL_STATE_IDLE) { if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) { currentPage++; //load more list items: loadElements(currentPage); } } }
donde
currentPage
es la página de su fuente de datos que debe agregarse a su lista, ythreshold
es el número de elementos de la lista (contados desde el final) que deberían, si están visibles, desencadenar el proceso de carga. si configurasthreshold
para0
por ejemplo, el usuario tiene que desplazarse hasta el final de la lista para cargar más elementos. -
(Opcional) Como puede ver, la “comprobación de carga adicional” solo se activa cuando el usuario deja de desplazarse. Para mejorar la usabilidad, puede inflar y agregar un indicador de carga al final de la lista a través de
listView.addFooterView(yourFooterView)
. Un ejemplo para tal vista de pie de página:<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/footer_layout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="10dp" > <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_gravity="center_vertical" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@+id/progressBar1" android:padding="5dp" android:text="@string/loading_text" /> </RelativeLayout>
-
(Opcional) Finalmente, elimine ese indicador de carga llamando
listView.removeFooterView(yourFooterView)
si no hay más elementos o páginas.
-
Intenté esto pero no funciona para ListFragment. ¿Cómo se puede usar en ListFragment.
– zeeshan
13 de julio de 2013 a las 15:35
-
Bueno, lo uso con
ListFragment
también sin ningún problema, solo siga cada uno de los pasos anteriores y estará bien;) ¿O podría proporcionar algún mensaje de error?– saschoar
14/07/2013 a las 21:44
-
Lo que podría haberse perdido se explica en esta respuesta SO: stackoverflow.com/a/6357957/1478093 –
getListView().setOnScrollListener(this)
– Tbieniek
24 de julio de 2013 a las 9:29
-
nota: agregar y eliminar el pie de página en la vista de lista es problemático (el pie de página no aparece si se llama a setAdapter antes de agregar el pie de página), terminé modificando la visibilidad de la vista del pie de página directamente sin eliminarlo.
– dvd
20/10/2013 a las 22:53
-
¿Qué se debe agregar en loadElements (currentPage)? Quiero decir, ¿llamo a mi AsyncTask o un hilo?
– desarrollador de Android
28 de noviembre de 2013 a las 8:19
dariusz bacinski
Puede detectar el final de la lista con la ayuda de onScrollListenerel código de trabajo se presenta a continuación:
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
Log.v(TAG, "onListEnd, extending list");
mPrevTotalItemCount = totalItemCount;
mAdapter.addMoreData();
}
}
Otra forma de hacerlo (adaptador interior) es la siguiente:
public View getView(int pos, View v, ViewGroup p) {
if(pos==getCount()-1){
addMoreData(); //should be asynctask or thread
}
return view;
}
Tenga en cuenta que este método se llamará muchas veces, por lo que debe agregar otra condición para bloquear varias llamadas de addMoreData()
.
Cuando agregue todos los elementos a la lista, llame al notificarDataSetChanged() dentro de su adaptador para actualizar la Vista (debe ejecutarse en el hilo de la interfaz de usuario – runOnUiThread)
-
Es una mala práctica hacer otras cosas además de devolver una vista en
getView
. Por ejemplo, no se le garantiza quepos
es visto por el usuario. Podría ser simplemente cosas de medición de ListView.– Tomas Ahle
13 de agosto de 2011 a las 10:10
-
Quiero cargar más elementos después de desplazar 10 elementos. pero me doy cuenta de que la carga comienza antes de que el décimo elemento sea visible en el noveno elemento. Entonces, ¿cómo detener esto?
– Atul Bhardwaj
31 de octubre de 2012 a las 6:44
oikonomopo
En Ognyan Bankov GitHub
¡Encontré una solución simple y funcional!
Hace uso de la Volley HTTP library
eso hace que la creación de redes para aplicaciones de Android sea más fácil y, lo que es más importante, más rápida. Volley está disponible a través del repositorio abierto de AOSP.
El código dado demuestra:
- ListView que se completa con solicitudes paginadas HTTP.
- Uso de NetworkImageView.
- Paginación ListView “sin fin” con lectura anticipada.
Para futura consistencia i repo bifurcado de Bankov.
fernando camargo
Aquí hay una solución que también facilita mostrar una vista de carga al final de ListView mientras se está cargando.
Puedes ver las clases aquí:
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java
– Ayudante para hacer posible el uso de las funciones sin extender desde SimpleListViewWithLoadingIndicator.
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java
– Oyente que comienza a cargar datos cuando el usuario está a punto de llegar al final de ListView.
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java
– El EndlessListView. Puede usar esta clase directamente o ampliarla.
tehcpu
Puede ser un poco tarde, pero la siguiente solución fue muy útil en mi caso. En cierto modo, todo lo que necesita hacer es agregar a su ListView un Footer
y crear para ello addOnLayoutChangeListener
.
http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)
Por ejemplo:
ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview
...
loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.d("Hey!", "Your list has reached bottom");
}
});
Este evento se activa una vez cuando un pie de página se vuelve visible y funciona a la perfección.
La clave de este problema es detectar el evento de carga adicional, iniciar una solicitud asíncrona de datos y luego actualizar la lista. También se necesita un adaptador con indicador de carga y otros decoradores. De hecho, el problema es muy complicado en algunos casos de esquina. solo un OnScrollListener
la implementación no es suficiente, porque a veces los elementos no llenan la pantalla.
He escrito un paquete personal que admite una lista interminable para RecyclerView
y también proporciona una implementación de cargador asíncrono AutoPagerFragment
lo que hace que sea muy fácil obtener datos de una fuente de varias páginas. Puede cargar cualquier página que desee en un RecyclerView
en un evento personalizado, no solo en la página siguiente.
Aquí está la direccción: https://github.com/SphiaTower/AutoPagerRecyclerManager
-
El enlace está roto.
– DSlomer64
3 sep 2017 a las 23:02
Recomiendo EndlessAdapter de CommonWare: github.com/commonsguy/cwac-endless. Lo encontré a partir de esta respuesta a otra pregunta: stackoverflow.com/questions/4667064/….
– Tyler Collier
7 de junio de 2011 a las 5:25
Necesito lo mismo… ¿alguien puede ayudarme?…stackoverflow.com/questions/28122304/…
– usuario4050065
30 de enero de 2015 a las 4:00