2009-07-03 15 views
220

Come posso creare un elenco in cui quando raggiungi la fine della lista mi viene notificato in modo che possa caricare più articoli?Elenco Android Endless

+9

Raccomando l'EndlessAdapter di CommonWare: http://github.com/commonsguy/cwac-endless. L'ho trovato da questa risposta a un'altra domanda: http://stackoverflow.com/questions/4667064/android-implementing-endless-list-like-android-market/4667102#4667102. –

+0

Ho bisogno della stessa cosa..può aiutare qualcuno? ..http: //stackoverflow.com/questions/28122304/endless-scrolling-listview-not-working –

risposta

266

Una soluzione è implementare un OnScrollListener e apportare modifiche (come l'aggiunta di elementi, ecc.) Allo ListAdapter in uno stato conveniente nel suo metodo onScroll.

Il seguente numero ListActivity mostra un elenco di numeri interi, a partire da 40, che aggiungono elementi quando l'utente scorre fino alla fine dell'elenco.

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; 
     } 
    } 
} 

Si dovrebbe, ovviamente, utilizzare thread separati per le azioni di gestione a lungo (come il caricamento web-dati) e potrebbe voler indicare i progressi nel corso dell'ultimo elemento della lista (come le applicazioni di mercato o Gmail fanno).

+3

eh, questo non farebbe scattare l'aumento della dimensione dell'adattatore se tu? d smettere di scorrere al centro dello schermo? dovrebbe solo caricare i successivi 10 quando raggiunge effettivamente la lista in basso. – Matthias

+9

Ho notato molti esempi come questo usando BaseAdapter. Volevo dire che se stai usando un database, prova ad usare SimpleCursorAdapter. Quando è necessario aggiungere all'elenco, aggiornare il database, ottenere un nuovo cursore e utilizzare SimpleCursorAdapter # changeCursor insieme a notifyDataSetChanged. Non è richiesta alcuna sottoclasse e funziona meglio di un BaseAdapter (di nuovo, solo se si sta utilizzando un database). – brack

+1

Dopo aver chiamato notifyDataSetChanged(), andrà in cima alla lista, come posso impedirlo? – draw

20

È possibile rilevare fine dell'elenco con l'aiuto di onScrollListener, il codice di lavoro è la seguente:

@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(); 
    } 
} 

Un altro modo per farlo (all'interno adattatore) è la seguente:

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

Be consapevole che questo metodo verrà chiamato più volte, quindi è necessario aggiungere un'altra condizione per bloccare più chiamate di addMoreData().

Quando si aggiungono tutti gli elementi alla lista, si prega di chiamare notifyDataSetChanged() all'interno dell'adattatore vostro per aggiornare la vista (che dovrebbe essere eseguito su thread UI - runOnUiThread)

+0

Modifica: aggiunto il metodo getView() –

+7

È una cattiva pratica fare altro che restituire una vista in 'getView'. Ad esempio, non è garantito che 'pos' venga visualizzato dall'utente. Potrebbe essere semplicemente un oggetto di misurazione ListView. –

+0

Voglio caricare più elementi dopo che sono stati fatti scorrere 10 articoli. ma noto che il caricamento inizia prima che il decimo elemento sia visibile significa sul nono articolo. Quindi come fermarlo? –

91

Volevo solo contribuire con una soluzione che ho usato per la mia app .

Si basa anche sull'interfaccia OnScrollListener, ma ho trovato che offre prestazioni di scorrimento molto migliori sui dispositivi di fascia bassa, poiché nessuno dei calcoli del conteggio totale/visibile viene eseguito durante le operazioni di scorrimento.

  1. Si compia la tua ListFragment o ListActivity implementare OnScrollListener
  2. Aggiungere i seguenti metodi per quella classe:

    @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); 
         } 
        } 
    } 
    

    dove currentPage è la pagina della tua origine dati che deve essere aggiunto alla vostra lista, e threshold è il numero di voci dell'elenco (contate dalla fine) che dovrebbero, se visibili, attivare il processo di caricamento. Se si imposta threshold su 0, ad esempio, l'utente deve scorrere fino alla fine dell'elenco per caricare più articoli.

  3. (facoltativo) Come si può vedere, il "controllo di sovraccarico" viene chiamato solo quando l'utente interrompe lo scorrimento. Per migliorare l'usabilità, è possibile gonfiare e aggiungere un indicatore di caricamento alla fine dell'elenco tramite listView.addFooterView(yourFooterView). Un esempio di una tale visione piè di pagina:

    <?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. (opzionale) Infine, rimuovere tale indicatore di caricamento chiamando listView.removeFooterView(yourFooterView) se non ci sono più elementi o pagine.

+0

Ho provato questo, ma non funziona per ListFragment. Come può essere utilizzato in ListFragment. – zeeshan

+0

Beh, lo uso anche con 'ListFragment' senza problemi - basta seguire ciascuno dei passaggi precedenti e starai bene;) Oppure potresti fornire qualche messaggio di errore? – saschoar

+0

Ciò che potresti aver perso è spiegato in questa risposta SO: http://stackoverflow.com/a/6357957/1478093 - 'getListView(). SetOnScrollListener (this)' – TBieniek

0

ho lavorato in un'altra soluzione molto simile a quello, ma, sto usando un footerView per dare la possibilità per l'utente a scaricare più elementi cliccando sul footerView, sto usando un "menu" che è mostrato sopra il ListView e nella parte inferiore della vista genitore, questo "menu" nasconde la parte inferiore del ListView, quindi, quando lo listView sta scorrendo il menu scompare e quando lo stato di scorrimento è inattivo, il menu appare di nuovo, ma quando l'utente scorre fino alla fine del listView, "chiedo" per sapere se il footerView è mostrato in quel caso, il menu non appare e l'utente può vedere il footerView per caricare più contenuti. Qui il codice:

Saluti.

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

Ecco una soluzione che rende anche più facile per una visualizzazione di carico alla fine del ListView mentre sta caricando.

Potete vedere le classi qui:

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java - Helper per rendere possibile l'utilizzo delle funzioni senza che si estende dal SimpleListViewWithLoadingIndicator.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Listener che avvia il caricamento dei dati quando l'utente sta per raggiungere il fondo di ListView.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java - The EndlessListView. Puoi usare direttamente questa classe o estenderla da essa.

4

Al Ognyan Bankov GitHub ho trovato una soluzione semplice e funzionante!

Utilizza lo Volley HTTP library che semplifica la connessione in rete per app Android e, soprattutto, più veloce. Volley è disponibile attraverso il repository AOSP aperto.

Il dato codice illustra:

  1. ListView che è popolata da richieste HTTP impaginati.
  2. Utilizzo di NetworkImageView.
  3. Impaginazione ListView "senza fine" con read-ahead.

Per consistenza futura i forked Bankov's repo.

0

La chiave di questo problema è rilevare l'evento più carico, avviare una richiesta asincrona per i dati e quindi aggiornare l'elenco. È necessario anche un adattatore con indicatore di carico e altri decoratori. In effetti, il problema è molto complicato in alcuni casi d'angolo. Solo un'implementazione OnScrollListener non è sufficiente, perché a volte gli elementi non riempiono lo schermo.

Ho scritto un pacchetto personale che supporta l'elenco infinito per RecyclerView e fornisce anche un'implementazione del caricatore asincrono AutoPagerFragment che rende molto facile ottenere dati da una sorgente di più pagine. Può caricare qualsiasi pagina desiderata in un RecyclerView su un evento personalizzato, non solo sulla pagina successiva.

Ecco l'indirizzo: https://github.com/SphiaTower/AutoPagerRecyclerManager

+0

Il collegamento è rotto. – DSlomer64

1

può essere un po 'in ritardo, ma la seguente soluzione successo molto utile nel mio caso. In un certo senso tutto ciò che devi fare è aggiungere a ListView un Footer e creare per esso addOnLayoutChangeListener.

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

Ad esempio:

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"); 
    } 
}); 

incendi di questo evento una volta quando un piè di pagina diventa visibile e funziona come un fascino.

0

La migliore soluzione finora trovata è la libreria FastAdapter per le visualizzazioni del riciclatore. Ha un EndlessRecyclerOnScrollListener.

Ecco un esempio di utilizzo: EndlessScrollListActivity

Una volta l'ho usato per la lista a scorrimento infinito mi sono reso conto che l'installazione è molto robusto. Lo raccomanderei sicuramente.