Wie kann ich eine Liste erstellen, bei der ich benachrichtigt werde, wenn Sie das Ende der Liste erreicht haben, um weitere Elemente laden zu können?
Eine Lösung besteht darin, eine OnScrollListener
zu implementieren und Änderungen an der ListAdapter
in einem geeigneten Zustand in ihrer onScroll
-Methode vorzunehmen (z. B. Elemente hinzufügen usw.).
Die folgende ListActivity
zeigt eine Liste von Ganzzahlen, beginnend mit 40, und fügt Elemente hinzu, wenn der Benutzer an das Ende der Liste blättert.
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;
}
}
}
Sie sollten natürlich separate Threads für lange ausgeführte Aktionen verwenden (z. B. das Laden von Webdaten). Möglicherweise möchten Sie den Fortschritt des letzten Listenelements anzeigen (wie dies bei Market- oder Google Mail-Apps der Fall ist).
Ich wollte nur eine Lösung beitragen, die ich für meine App verwendet habe.
Es basiert ebenfalls auf der OnScrollListener
-Schnittstelle, aber ich habe festgestellt, dass es auf Low-End-Geräten eine viel bessere Bildlaufleistung bietet, da während der Bildlaufoperationen keine der sichtbaren Gesamtzählungen durchgeführt wird.
ListFragment
oder ListActivity
OnScrollListener
implementierenFügen Sie dieser Klasse die folgenden Methoden hinzu:
@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);
}
}
}
dabei ist currentPage
die Seite Ihrer Datenquelle, die Ihrer Liste hinzugefügt werden soll, und threshold
die Anzahl der Listenelemente (ab Ende gezählt), die den Ladevorgang auslösen sollen, wenn sie sichtbar sind. Wenn Sie beispielsweise threshold
auf 0
setzen, muss der Benutzer bis zum Ende der Liste blättern, um weitere Elemente laden zu können.
(optional) Wie Sie sehen, wird der "load-more check" nur aufgerufen, wenn der Benutzer den Bildlauf stoppt. Um die Benutzerfreundlichkeit zu verbessern, können Sie mit listView.addFooterView(yourFooterView)
einen Ladeindikator hinzufügen und am Ende der Liste hinzufügen. Ein Beispiel für eine solche Fußzeile:
<?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>
(optional) Zum Schluss entfernen Sie das Ladekennzeichen, indem Sie listView.removeFooterView(yourFooterView)
aufrufen, wenn keine weiteren Elemente oder Seiten vorhanden sind.
Sie können das Ende der Liste mit Hilfe von onScrollListener erkennen. Der folgende Arbeitscode wird angezeigt:
@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();
}
}
Eine andere Möglichkeit, dies (innerhalb des Adapters) zu tun, ist wie folgt:
public View getView(int pos, View v, ViewGroup p) {
if(pos==getCount()-1){
addMoreData(); //should be asynctask or thread
}
return view;
}
Beachten Sie, dass diese Methode mehrmals aufgerufen wird. Sie müssen also eine weitere Bedingung hinzufügen, um mehrere Aufrufe von addMoreData()
zu blockieren.
Wenn Sie der Liste alle Elemente hinzufügen, rufen Sie bitte notifyDataSetChanged () in Ihrem Adapter auf, um die Ansicht zu aktualisieren (sie sollte auf dem UI-Thread ausgeführt werden - runOnUiThread ).
Bei Ognyan Bankov GitHub
habe ich eine einfache und funktionierende Lösung gefunden!
Es verwendet das Volley HTTP library
, das die Vernetzung für Android-Apps einfacher und vor allem schneller macht. Volley ist über das offene AOSP-Repository verfügbar.
Der angegebene Code zeigt:
Für die zukünftige Konsistenz i gegabeltes Repo von Bankov .
Hier ist eine Lösung, mit der es auch einfach ist, eine Ladeansicht am Ende der ListView anzuzeigen, während sie geladen wird.
Sie können die Klassen hier sehen:
https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.Java - Helper um die Verwendung der Funktionen zu ermöglichen, ohne von SimpleListViewWithLoadingIndicator erweitert zu werden.
https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.Java - Listener Dadurch beginnt das Laden von Daten, wenn der Benutzer das Ende der ListView erreicht.
https://github.com/CyberEagle/OpenProjects/blob/master/Android-projects/widgets/src/main/Java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.Java - The EndlessListView. Sie können diese Klasse direkt verwenden oder daraus erweitern.
Vielleicht etwas spät, aber die folgende Lösung ist in meinem Fall sehr nützlich. In gewisser Weise müssen Sie lediglich eine Footer
zu Ihrer ListView hinzufügen und dafür addOnLayoutChangeListener
erstellen.
http://developer.Android.com/reference/Android/widget/ListView.html#addFooterView(Android.view.View)
Zum Beispiel:
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");
}
});
Dieses Ereignis wird einmal ausgelöst, wenn eine Fußzeile sichtbar wird und wie ein Zauber wirkt.
Die beste Lösung, die ich bisher gesehen habe, ist in FastAdapter library für Recycler-Ansichten. Es hat eine EndlessRecyclerOnScrollListener
.
Hier ein Beispiel für eine Verwendung: EndlessScrollListActivity
Nachdem ich es für endlose Bildlauflisten verwendet hatte, wurde mir klar, dass das Setup sehr robust ist. Ich würde es auf jeden Fall empfehlen.
Ich habe in einer anderen Lösung gearbeitet, die dem sehr ähnlich ist, aber ich verwende eine footerView
, um dem Benutzer die Möglichkeit zu geben, weitere Elemente herunterzuladen, die auf footerView
klicken. Ich verwende ein "Menü", das wird über der ListView
angezeigt, und im unteren Bereich der übergeordneten Ansicht verdeckt dieses "Menü" die Unterseite der ListView
. Wenn also mit listView
gescrollt wird, verschwindet das Menü und beim Scrollen Wenn der Benutzer bis zum Ende der Option listView
blättert, frage ich, ob in diesem Fall die Option footerView
angezeigt wird, und das Menü wird nicht angezeigt und der Benutzer kann die footerView
sehen, um mehr Inhalt zu laden. Hier der Code:
Grüße.
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) {
}
});
Ich weiß, es ist eine alte Frage und die Android Welt ist größtenteils zu RecyclerViews übergegangen, aber für alle Interessierten ist die this Bibliothek vielleicht sehr interessant.
Es verwendet den BaseAdapter, der mit der ListView verwendet wird, um zu erkennen, wann die Liste zum letzten Element gescrollt wurde oder wann sie vom letzten Element weg gescrollt wird.
Zum Lieferumfang gehört ein Beispielprojekt (kaum 100 Zeilen Aktivitätscode), mit dem Sie schnell verstehen können, wie es funktioniert.
Einfache Bedienung:
class Boy{
private String name;
private double height;
private int age;
//Other code
}
Ein Adapter zum Halten von Boy-Objekten sieht folgendermaßen aus:
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);
}
Beachten Sie, wie die getView-Methode von BoysAdapter einen Aufruf an die getView
-Methode der EndlessAdapter-Oberklasse zurückgibt. Dies ist zu 100% unerlässlich.
Gehen Sie wie folgt vor, um den Adapter zu erstellen:
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);
}
}
};
Das loadMore
-Element ist eine Schaltfläche oder ein anderes UI-Element, auf das geklickt werden kann, um weitere Daten aus der URL abzurufen. Wenn der Adapter wie im Code beschrieben platziert ist, weiß er genau, wann diese Schaltfläche angezeigt und wann sie deaktiviert werden muss. Erstellen Sie einfach die Schaltfläche in Ihrer XML und platzieren Sie sie wie im obigen Adaptercode gezeigt.
Genießen.
Der Schlüssel dieses Problems besteht darin, das Ereignis "mehr laden" zu erkennen, eine asynchrone Datenanforderung zu starten und dann die Liste zu aktualisieren. Außerdem wird ein Adapter mit Ladeanzeige und anderen Dekorateuren benötigt. Tatsächlich ist das Problem in einigen Eckfällen sehr kompliziert. Eine OnScrollListener
-Implementierung reicht nicht aus, da die Elemente manchmal den Bildschirm nicht ausfüllen.
Ich habe ein persönliches Paket geschrieben, das eine endlose Liste für RecyclerView
unterstützt und außerdem eine async-loader-Implementierung AutoPagerFragment
zur Verfügung stellt, die es sehr einfach macht, Daten aus einer mehrseitigen Quelle abzurufen. Es kann jede beliebige Seite in eine RecyclerView
eines benutzerdefinierten Ereignisses laden, nicht nur die nächste Seite.
Hier ist die Adresse: https://github.com/SphiaTower/AutoPagerRecyclerManager