2009-07-03 10 views
220

¿Cómo puedo crear una lista en la que cuando llego al final de la lista reciba una notificación para poder cargar más artículos?Android Endless List

+9

Recomiendo el EndlessAdapter de CommonWare: http://github.com/commonsguy/cwac-endless. Lo encontré desde esta respuesta a otra pregunta: http://stackoverflow.com/questions/4667064/android-implementing-endless-list-like-android-market/4667102#4667102. –

+0

Necesito lo mismo ... ¿puedo ayudar a alguien? ..http: //stackoverflow.com/questions/28122304/endless-scrolling-listview-not-working –

Respuesta

266

Una solución es implementar un OnScrollListener y realizar cambios (como agregar elementos, etc.) al ListAdapter en un estado conveniente en su método onScroll.

La siguiente ListActivity muestra una lista de 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 utilizar hilos separados para las acciones de larga ejecución (como la carga de datos web) y puede ser que desee para indicar el progreso en el último elemento de la lista (como las aplicaciones de mercado o de Gmail lo hacen).

+3

¿no, esto no dispararía el tamaño del adaptador si aumentase? ¿Dejo de desplazarme en el medio de la pantalla? solo debería cargar los próximos 10 cuando realmente llegue a la parte inferior de la lista. – Matthias

+9

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 notifyDataSetChanged. No se requieren subclases, y funciona mejor que un BaseAdapter (nuevamente, solo si está usando una base de datos). – brack

+1

Después de llamar a notifyDataSetChanged(), irá a la parte superior de la lista, ¿cómo puedo evitarlo? – draw

20

Puede detectar final de la lista con la ayuda de onScrollListener, el 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 manera de hacerlo (en el interior del adaptador) es como sigue:

public View getView(int pos, View v, ViewGroup p) { 
      if(pos==getCount()-1){ 
       addMoreData(); //should be asynctask or thread 
      } 
      return view; 
    } 

Sea consciente de que se llamará este método muchas veces, por lo que debe agregar otra condición para bloquear varias llamadas de addMoreData().

Cuando se agrega todos los elementos a la lista, por favor llame a notifyDataSetChanged() dentro del adaptador suyo para actualizar la vista (que se debe ejecutar en el subproceso de interfaz de usuario - runOnUiThread)

+0

Editar: método getView() agregado –

+7

Es una mala práctica hacer otras cosas que devolver una vista en 'getView'. Por ejemplo, no se garantiza que 'pos' sea visto por el usuario. Podría ser simplemente ListView midiendo cosas. –

+0

Quiero cargar más artículos después de que se hayan desplazado 10 elementos. pero noto que la carga comienza antes de que el 10º elemento sea visible significa que está en el 9º elemento. Entonces, ¿cómo detener esto? –

91

Sólo quería contribuir con una solución que he usado para mi aplicación .

También se basa en la interfaz OnScrollListener, pero encontré que tiene un rendimiento de desplazamiento mucho mejor en dispositivos de gama baja, ya que ninguno de los cálculos de recuento total/visible se llevan a cabo durante las operaciones de desplazamiento.

  1. Deje que su ListFragment o ListActivity implemento OnScrollListener
  2. Añadir los siguientes métodos para 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 ser agregado a la lista, y threshold es el número de elementos de la lista (contados desde el final) que, de ser visibles, deberían desencadenar el proceso de carga. Si configura threshold en 0, por ejemplo, el usuario tiene que desplazarse hasta el final de la lista para cargar más elementos.

  3. (opcional) Como se puede ver, la "carga-más de verificación" interviene sólo cuando el usuario deja de moverse. Para mejorar la usabilidad, puede inflar y agregar un indicador de carga al final de la lista a través del listView.addFooterView(yourFooterView). Un ejemplo de una vista de este 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> 
    
  4. (opcional) Por último, eliminar ese indicador de carga llamando listView.removeFooterView(yourFooterView) si no hay más artículos o páginas.

+0

Intenté esto pero no funciona para ListFragment. ¿Cómo se puede usar en ListFragment? – zeeshan

+0

Bueno, también lo uso con 'ListFragment' 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

+0

Lo que podría haber omitido se explica en esta respuesta SO: http://stackoverflow.com/a/6357957/1478093 - 'getListView(). SetOnScrollListener (esto)' – TBieniek

0

He estado trabajando en otra solución muy similar a eso, sino que, estoy usando un footerView para dar la posibilidad al usuario descargar más elementos clic en el footerView, estoy usando un "menú", que es se muestra arriba de ListView y en la parte inferior de la vista principal, este "menú" oculta la parte inferior de ListView, por lo tanto, cuando el listView se desplaza, el menú desaparece y cuando el estado de desplazamiento está inactivo, el menú aparece nuevamente, pero cuando el usuario se desplaza hasta el final de listView, pregunto si el footerView se muestra en ese caso, el menú no aparece y el usuario puede ver el footerView para cargar más contenido. Aquí el código:

Saludos.

listView.setOnScrollListener(new OnScrollListener() { 

    @Override 
    public void onScrollStateChanged(AbsListView view, int scrollState) { 
     // TODO Auto-generated method stub 
     if(scrollState == SCROLL_STATE_IDLE) { 
      if(footerView.isShown()) { 
       bottomView.setVisibility(LinearLayout.INVISIBLE); 
      } else { 
       bottomView.setVisibility(LinearLayout.VISIBLE); 
      } else { 
       bottomView.setVisibility(LinearLayout.INVISIBLE); 
      } 
     } 
    } 

    @Override 
    public void onScroll(AbsListView view, int firstVisibleItem, 
      int visibleItemCount, int totalItemCount) { 

    } 
}); 
2

Aquí es una solución que también hace que sea fácil mostrar una vista de carga en el extremo de la ListView mientras se está cargando.

Puede 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 que sea posible el uso de las características sin que se extiende desde SimpleListViewWithLoadingIndicator.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Escucha 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 - The EndlessListView. Puedes usar esta clase directamente o extender desde ella.

4

¡En Ognyan Bankov GitHub encontré una solución simple y de trabajo!

Hace uso del Volley HTTP library que hace que las redes para aplicaciones de Android sean más fáciles y, lo que es más importante, más rápidas. Volley está disponible a través del repositorio AOSP abierto.

el código dado demuestra:

  1. ListView que está poblada por peticiones HTTP paginados.
  2. Uso de NetworkImageView.
  3. "sin fin" ListView paginación con lectura anticipada.

Para consistencia futura i forked Bankov's repo.

0

La clave de este problema es detectar el evento load-more, iniciar una solicitud asincrónica 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 una implementación de OnScrollListener no es suficiente, porque a veces los elementos no llenan la pantalla.

He escrito un paquete personal que admite la lista interminable para RecyclerView, y también proporciono una implementación de cargador asíncrono AutoPagerFragment 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 dirección: https://github.com/SphiaTower/AutoPagerRecyclerManager

+0

El enlace está roto. – DSlomer64

1

puede ser un poco tarde, pero la siguiente solución sucedido muy útil en mi caso. De una manera, todo lo que necesita hacer es agregar a su ListaVer un Footer y crear para él 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"); 
    } 
}); 

incendios este evento una vez cuando un pie de página se hace visible y funciona como un encanto.

0

La mejor solución hasta ahora que he visto está en la biblioteca FastAdapter para recicladores. Tiene un EndlessRecyclerOnScrollListener.

Aquí es un ejemplo de uso: EndlessScrollListActivity

Una vez que lo usé para la lista de desplazamiento sin fin me he dado cuenta de que la configuración es un muy robusto. Definitivamente lo recomendaría.