Come posso creare un elenco in cui quando si raggiunge la fine dell'elenco sono stato avvisato in modo da poter caricare più elementi?
Come posso creare un elenco in cui quando si raggiunge la fine dell'elenco sono stato avvisato in modo da poter caricare più elementi?
Risposte:
Una soluzione consiste nell'implementare OnScrollListener
e apportare modifiche (come aggiungere elementi, ecc.) ListAdapter
A uno stato conveniente nel suo onScroll
metodo.
Di seguito viene ListActivity
mostrato un elenco di numeri interi, che iniziano con 40, aggiungendo 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;
}
}
}
Ovviamente dovresti usare thread separati per azioni di lunga durata (come il caricamento di dati web) e potresti voler indicare i progressi nell'ultimo elemento dell'elenco (come fanno le app di mercato o di Gmail).
firstVisible + visibleCount >= totalCount
è soddisfatta più volte con più chiamate all'ascoltatore. Se la funzione load-more è una richiesta Web, (molto probabilmente lo sarà), aggiungi un altro controllo per verificare se una richiesta è in corso o meno. D'altra parte, controlla se totalCount non è uguale al conteggio totale precedente, perché non abbiamo bisogno di più richieste per lo stesso numero di elementi nell'elenco.
Volevo solo contribuire con una soluzione che ho usato per la mia app.
Si basa anche OnScrollListener
sull'interfaccia, ma ho scoperto che ha 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.
ListFragment
o ListActivity
implementareOnScrollListener
Aggiungi i seguenti metodi a 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 si currentPage
trova la pagina dell'origine dati da aggiungere all'elenco e threshold
il numero di elementi dell'elenco (conteggiati alla fine) che, se visibili, dovrebbero attivare il processo di caricamento. Se si imposta threshold
a 0
, per esempio, l'utente deve scorrere fino alla fine della lista, al fine di caricare più elementi.
(facoltativo) Come puoi vedere, il "controllo di caricamento più" viene chiamato solo quando l'utente smette di scorrere. Per migliorare l'usabilità, è possibile gonfiare e aggiungere un indicatore di caricamento alla fine dell'elenco tramite listView.addFooterView(yourFooterView)
. Un esempio per tale vista a 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>
(facoltativo) Infine, rimuovi quell'indicatore di caricamento chiamando listView.removeFooterView(yourFooterView)
se non ci sono più elementi o pagine.
ListFragment
senza problemi - basta seguire ciascuno dei passaggi sopra e andrà tutto bene;) O potresti fornire messaggi di errore?
getListView().setOnScrollListener(this)
È possibile rilevare la fine dell'elenco con l'aiuto di onScrollListener , il codice di lavoro è presentato di seguito:
@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 dell'adattatore) è il seguente:
public View getView(int pos, View v, ViewGroup p) {
if(pos==getCount()-1){
addMoreData(); //should be asynctask or thread
}
return view;
}
Tieni presente che questo metodo verrà chiamato molte volte, quindi devi aggiungere un'altra condizione per bloccare più chiamate addMoreData()
.
Quando aggiungi tutti gli elementi all'elenco, chiama notifyDataSetChanged () all'interno dell'adattatore per aggiornare la vista (dovrebbe essere eseguito sul thread dell'interfaccia utente - runOnUiThread )
getView
. Ad esempio, non sei garantito che pos
venga visualizzato dall'utente. Potrebbe essere semplicemente la misurazione di ListView.
A Ognyan Bankov GitHub
ho trovato una soluzione semplice e funzionante!
Si avvale di Volley HTTP library
ciò che rende la rete per le app Android più semplice e, soprattutto, più veloce. Volley è disponibile tramite il repository AOSP aperto.
Il codice fornito dimostra:
Per consistenza futura ho modificato il repository di Bankov .
Ecco una soluzione che semplifica anche la visualizzazione di una vista di caricamento alla fine di ListView durante il caricamento.
Puoi vedere le lezioni 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'uso di funzioni senza estensione da SimpleListViewWithLoadingIndicator.
https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java - Listener che inizia a caricare i dati quando l'utente sta per raggiungere la parte inferiore 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 questa classe direttamente o estenderla.
Potrebbe essere un po 'tardi, ma la seguente soluzione è stata molto utile nel mio caso. In un certo senso, tutto ciò che devi fare è aggiungere a ListView a Footer
e crearlo addOnLayoutChangeListener
.
http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)
Per 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");
}
});
Questo evento si attiva una volta quando un piè di pagina diventa visibile e funziona come un incantesimo.
La chiave di questo problema è rilevare l'evento load-more, avviare una richiesta asincrona per i dati e quindi aggiornare l'elenco. Inoltre è necessario un adattatore con indicatore di caricamento e altri decoratori. In effetti, il problema è molto complicato in alcuni casi angolari. Solo OnScrollListener
un'implementazione non è sufficiente, perché a volte gli elementi non riempiono lo schermo.
Ho scritto un pacchetto personale che supporta un elenco infinito RecyclerView
e fornisce anche un'implementazione del caricatore asincrono AutoPagerFragment
che rende molto facile ottenere dati da una fonte multi-pagina. Può caricare qualsiasi pagina in un RecyclerView
evento personalizzato, non solo la pagina successiva.
Ecco l'indirizzo: https://github.com/SphiaTower/AutoPagerRecyclerManager
La migliore soluzione finora che ho visto è nella libreria FastAdapter per le visualizzazioni dei riciclatori. Ha un EndlessRecyclerOnScrollListener
.
Ecco un esempio di utilizzo: EndlessScrollListActivity
Una volta che l'ho usato per una lista a scorrimento infinita mi sono reso conto che l'installazione è molto robusta. Lo consiglio vivamente.
Ho lavorato in un'altra soluzione molto simile a quella, ma, sto usando un footerView
per dare la possibilità all'utente di scaricare più elementi facendo clic su footerView
, sto usando un "menu" che viene mostrato sopra ListView
e nella parte inferiore della vista genitore, questo "menu" nasconde la parte inferiore del ListView
, quindi, quando il listView
menu a scorrimento scorre scompare e quando lo stato di scorrimento è inattivo, il menu appare di nuovo, ma quando l'utente scorre fino alla fine del listView
, "Chiedo" di sapere se footerView
viene visualizzato in quel caso, il menu non viene visualizzato e l'utente può vedere il footerView
caricamento di più contenuti. Ecco 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) {
}
});
So che è una vecchia domanda e il mondo Android è passato principalmente a RecyclerViews, ma per chiunque sia interessato, potresti trovare questa libreria molto interessante.
Utilizza BaseAdapter utilizzato con ListView per rilevare quando l'elenco è stato fatto scorrere fino all'ultimo elemento o quando è stato fatto scorrere lontano dall'ultimo elemento.
Viene fornito con un progetto di esempio (appena 100 righe di codice attività) che può essere utilizzato per capire rapidamente come funziona.
Semplice utilizzo:
class Boy{
private String name;
private double height;
private int age;
//Other code
}
Un adattatore per contenere oggetti Boy sarebbe simile a:
public class BoysAdapter extends EndlessAdapter<Boy>{
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent
.getContext());
holder = new ViewHolder();
convertView = inflater.inflate(
R.layout.list_cell, parent, false);
holder.nameView = convertView.findViewById(R.id.cell);
// minimize the default image.
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Boy boy = getItem(position);
try {
holder.nameView.setText(boy.getName());
///Other data rendering codes.
} catch (Exception e) {
e.printStackTrace();
}
return super.getView(position,convertView,parent);
}
Notare come il metodo getView di BoysAdapter restituisce una chiamata al getView
metodo della superclasse EndlessAdapter . Questo è essenziale al 100%.
Ora per creare l'adattatore, eseguire:
adapter = new ModelAdapter() {
@Override
public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {
if (moreItemsCouldBeAvailable) {
makeYourServerCallForMoreItems();
} else {
if (loadMore.getVisibility() != View.VISIBLE) {
loadMore.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onScrollAwayFromBottom(int currentIndex) {
loadMore.setVisibility(View.GONE);
}
@Override
public void onFinishedLoading(boolean moreItemsReceived) {
if (!moreItemsReceived) {
loadMore.setVisibility(View.VISIBLE);
}
}
};
L' loadMore
elemento è un pulsante o un altro elemento dell'interfaccia utente su cui è possibile fare clic per recuperare più dati dall'URL. Se posizionato come descritto nel codice, l'adattatore sa esattamente quando mostrare quel pulsante e quando disabilitarlo. Basta creare il pulsante nel tuo XML e posizionarlo come mostrato nel codice dell'adattatore sopra.
Godere.